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,85 @@
1
+ import { Vec3 } from "../../math/vec";
2
+ import type { KneeAxisReport, StepHandler } from "./core";
3
+ /** The feet settings (`anim.feet.set()` / the properties of `anim.feet`). Distances are metres, times
4
+ * seconds. Every key is optional and only the keys given change. */
5
+ export type FeetOptions = {
6
+ /** The contact bones per side — `'LeftFoot'`, or with a toe / ball `['LeftFoot', 'LeftToeBase']`.
7
+ * Default: classified from the bone names (Mixamo / Unity / Blender / UE). Setting them re-bakes
8
+ * every clip's contacts and phase. */
9
+ left?: string | string[];
10
+ right?: string | string[];
11
+ /** FOOT LOCK: a foot the shown clip calls planted is pinned where it landed — heel to ball, rolling
12
+ * as the clip rolls — and the leg re-solved to keep it there while the body moves on. Off by default. */
13
+ lock?: boolean;
14
+ /** GROUND IK: each foot is put on the ground the engine probes under it (stairs, a slope, a kerb),
15
+ * aligned to its normal, the pelvis lowered so the leg can reach. Needs a physics world to probe;
16
+ * without one the ground is the node's own plane. Off by default. */
17
+ ik?: boolean;
18
+ /** How far the pelvis may drop for the ground (default 0.35). */
19
+ pelvis?: number;
20
+ /** A locked foot never absorbs more residual than this — beyond it the anchor follows the animation
21
+ * instead of fighting it (default 0.10). */
22
+ unlockDistance?: number;
23
+ /** The lock's ease in / out, seconds (default 0.08 / 0.12). */
24
+ lockIn?: number;
25
+ lockOut?: number;
26
+ /** 0..1: how much the foot tilts onto the ground normal (default 1). */
27
+ align?: number;
28
+ /** The probe ray's reach above and below the ankle (default 0.6). */
29
+ probe?: number;
30
+ /** The lock plants only once the animated ankle moves slower than this, m/s (default 0.2). Raise it
31
+ * to pin a foot a transition is still dragging. */
32
+ plantSpeed?: number;
33
+ };
34
+ /** One foot after this frame's evaluation (`anim.feet.state(side)`): whether the lock holds it, the
35
+ * lock's weight (eased 0…1), where it was pinned and where the leg was asked to put the ankle — all world. */
36
+ export type FootState = {
37
+ locked: boolean;
38
+ weight: number;
39
+ anchor: Vec3;
40
+ target: Vec3;
41
+ };
42
+ export declare class Feet {
43
+ private readonly _c;
44
+ private readonly _o;
45
+ /** Change several settings at once; only the keys given change. Chainable. */
46
+ set(options: FeetOptions): this;
47
+ /** The current settings (what was set; unset keys are the engine's defaults). */
48
+ get options(): Readonly<FeetOptions>;
49
+ get lock(): boolean;
50
+ set lock(v: boolean);
51
+ get ik(): boolean;
52
+ set ik(v: boolean);
53
+ get pelvis(): number;
54
+ set pelvis(v: number);
55
+ get unlockDistance(): number;
56
+ set unlockDistance(v: number);
57
+ get lockIn(): number;
58
+ set lockIn(v: number);
59
+ get lockOut(): number;
60
+ set lockOut(v: number);
61
+ get align(): number;
62
+ set align(v: number);
63
+ get probe(): number;
64
+ set probe(v: number);
65
+ get plantSpeed(): number;
66
+ set plantSpeed(v: number);
67
+ /** The contact bones (`undefined` = classified from the names). */
68
+ get left(): string | string[] | undefined;
69
+ set left(v: string | string[] | undefined);
70
+ get right(): string | string[] | undefined;
71
+ set right(v: string | string[] | undefined);
72
+ /** One foot's state after this frame's evaluation — where the lock holds it and with what weight
73
+ * (a debug beam under the foot). `undefined` on a host without the feet stage, or before anything played. */
74
+ state(side: "left" | "right"): FootState | undefined;
75
+ /** The skeleton's calibrated KNEE HINGE AXIS for a side (thigh-local, unit) with its confidence report —
76
+ * measured once over every bound clip's knee rotation track. `undefined` = no leg chain, or no knee
77
+ * motion bound to calibrate from. */
78
+ kneeAxis(side: "left" | "right"): KneeAxisReport | undefined;
79
+ /** A foot planted (world position) — audio, dust, decals. Fires for what the BASE layer shows, from
80
+ * the clip's own contacts; a clip with no contacts fires nothing. */
81
+ onStep(cb: StepHandler): this;
82
+ offStep(cb: StepHandler): this;
83
+ private pushBones;
84
+ private push;
85
+ }
@@ -0,0 +1,53 @@
1
+ /** What `anim.warp` turns on. Speeds are m/s, angles degrees, distances metres. */
2
+ export type WarpOptions = {
3
+ /** Fit the stride to the speed the body actually travels at. `[min, max]` clamps the scale (default
4
+ * 0.85…1.2). A CORRECTION: a pack whose takes already read right at the speeds it is played at wants
5
+ * none of this; open the range for a pack that must cover speeds it was never recorded at. */
6
+ stride?: boolean | [number, number];
7
+ /** Turn the lower body toward where the body really travels; a number caps the turn in degrees
8
+ * (default 20). The whole twist lives in one joint: a few degrees read as a lean, a lot as a broken
9
+ * back. Only applied while the gait LOOP shows — a start, a turn or a stop walks a path of its own. */
10
+ orientation?: boolean | number;
11
+ /** Below this speed — the game's or the clip's — both warps are off (default 0.2). */
12
+ minSpeed?: number;
13
+ /** How far the pelvis may drop to keep a stretched leg from locking straight (default 0.25). */
14
+ pelvis?: number;
15
+ /** The stride scale's own spring, seconds (default 0.15): the shown clip's recorded speed steps at every
16
+ * switch, so the scale is smoothed rather than followed. */
17
+ strideTime?: number;
18
+ };
19
+ /** STEP WARP dials (`anim.warp.step`): `stride` scales each foot's travel-direction offset from its hip,
20
+ * `lift` = metres ADDED to its height (swing-gated; negative = a shuffle; half of it raises the pelvis),
21
+ * `pitch` (degrees, + = toes up) rotates each foot about its lateral axis, `slope` (degrees, + = ascending)
22
+ * the invisible staircase — feet on the incline, auto pitch, the character raised to hold each planted
23
+ * foot on its tread. A tuning bench's dial; locomotion will drive this itself later. */
24
+ export type StepWarpOptions = {
25
+ stride?: number;
26
+ lift?: number;
27
+ pitch?: number;
28
+ slope?: number;
29
+ };
30
+ export declare class Warp {
31
+ private readonly _c;
32
+ private _o;
33
+ private _step;
34
+ /** Replace the settings: `true` = both warps with the defaults, `false` / `{}` = off, or the options.
35
+ * (Replaces, does not merge — what is not asked for is off.) Chainable. */
36
+ set(w: WarpOptions | boolean): this;
37
+ /** The current settings. */
38
+ get options(): Readonly<WarpOptions>;
39
+ get stride(): boolean | [number, number];
40
+ set stride(v: boolean | [number, number]);
41
+ get orientation(): boolean | number;
42
+ set orientation(v: boolean | number);
43
+ get minSpeed(): number;
44
+ set minSpeed(v: number);
45
+ get pelvis(): number;
46
+ set pelvis(v: number);
47
+ get strideTime(): number;
48
+ set strideTime(v: number);
49
+ /** The step warp dials; `null` = off. */
50
+ get step(): StepWarpOptions | null;
51
+ set step(v: StepWarpOptions | null | undefined);
52
+ private push;
53
+ }
@@ -6,18 +6,17 @@ import { Vec3 } from "../../math/vec";
6
6
  import type { Node } from "../Node";
7
7
  /** A position on a blend axis (1D) or plane (2D). */
8
8
  export type BlendPosition = number | readonly [number, number];
9
- /** The transition time (seconds) a play / playLoop without `fade` uses. */
10
- export declare const DEFAULT_FADE = 0.2;
11
9
  export type PlayOptions = {
12
- /** Transition seconds — how long the difference to the pose the layer SHOWED takes to decay
13
- * (default 0.2; `0` = cut). Also the transition back at the end unless `fadeOut` overrides it. */
10
+ /** Transition seconds — how long the difference to the pose the layer SHOWED (its loop, a one-shot,
11
+ * or rest) takes to decay. Default `0` = cut: a fade is always asked for, never implied. Also the
12
+ * transition back to the loop at the end unless `fadeOut` overrides it. */
14
13
  fade?: number;
15
14
  /** Transition seconds for the way in only (overrides `fade`). */
16
15
  fadeIn?: number;
17
- /** One-shots: the transition BACK at the end (overrides `fade`). It starts this long before the
18
- * clip ends — while it still plays — so the hand-over lands on the last pose, not after it. On a
19
- * layer with no loop to return to, giving `fadeOut` releases the layer at the end instead of
20
- * holding the last frame. */
16
+ /** One-shots: the transition BACK to the loop at the end (overrides `fade`; `0` = cut at the end).
17
+ * It starts this long before the clip ends — while it still plays — so the hand-over lands on the
18
+ * last pose, not after it. On a layer with no loop the clip HOLDS its last frame (a rock that broke
19
+ * stays broken) — `anim.stop({ fade })` is the way back to rest. */
21
20
  fadeOut?: number;
22
21
  /** Playback rate for this clip (default 1). */
23
22
  speed?: number;
@@ -39,8 +38,8 @@ export type StopOptions = {
39
38
  fade?: number;
40
39
  };
41
40
  export type LoopOptions = {
42
- /** Transition seconds from whatever the layer shows — its previous loop, or a one-shot still
43
- * playing (default 0.2; `0` = cut). */
41
+ /** Transition seconds from whatever the layer shows — its previous loop, a one-shot still playing,
42
+ * or rest. Default `0` = cut: a loop wanting a transition asks for one (`{ fade: 0.2 }`). */
44
43
  fade?: number;
45
44
  /** Playback rate of the loop's clips (default 1). */
46
45
  speed?: number;
@@ -48,8 +47,17 @@ export type LoopOptions = {
48
47
  * over from a start / turn clip wants). The members share one clock, so this is every member's phase. */
49
48
  phase?: number | "match";
50
49
  };
51
- /** What a layer loops: one clip (name / index), or a blend space `{ name: position }`. */
52
- export type LoopDef = string | number | Record<string, BlendPosition>;
50
+ /** A blend member with its CYCLE given explicitly: `at` = its position, `offset` = its gait phase at t = 0
51
+ * (0 = a left-foot-down, 0.5 = a right-foot-down, 0–1), `cycles` = how many gait cycles the clip holds
52
+ * (a two-stride loop: 2). Both are measured offline from the clip's foot marks. Members given as a
53
+ * bare position run in normalized time and have no cycle (nothing phase-matches to them). */
54
+ export type BlendMember = {
55
+ at: BlendPosition;
56
+ offset?: number;
57
+ cycles?: number;
58
+ };
59
+ /** What a layer loops: one clip (name / index), or a blend space `{ name: position | { at, offset, cycles } }`. */
60
+ export type LoopDef = string | number | Record<string, BlendPosition | BlendMember>;
53
61
  /** One clip the layer shows this frame — `layer.active` / `anim.active` (a debug overlay's list). */
54
62
  export type ActiveClip = {
55
63
  name: string;
@@ -73,9 +81,28 @@ export type LayerOptions = {
73
81
  export type ClipEventHandler = (clip: string, layer: Layer) => void;
74
82
  /** A foot planted: which one, and where in the world it landed. */
75
83
  export type StepHandler = (side: "left" | "right", position: Vec3) => void;
76
- /** What the engine measured on a clip once it was bound to this skeleton (`anim.curves('Walk')`).
84
+ /** A loop's GAIT CYCLE as two numbers — what a blend member's `{ offset, cycles }` wants: φ(t) = offset +
85
+ * cycles · t / duration, 0 = a left-foot-down. `residual` = the worst foot-down's distance from that line
86
+ * (cycles; a clean loop sits under 0.03), `steps` = the foot-downs it was fitted through. */
87
+ export type ClipCycle = {
88
+ offset: number;
89
+ cycles: number;
90
+ residual: number;
91
+ steps: number;
92
+ };
93
+ /** A loop's cycle found by POSE against a reference loop (`clipInfo(clip).alignTo(ref)`): the `{ offset,
94
+ * cycles }` under which it shows the reference's pose at the reference's phase. `score` = the fit at that
95
+ * alignment (metres, the joint distance + velocity measure), `margin` = how much worse the runner-up
96
+ * alignment ≥ 0.2 cycle away is — near 0 means ambiguous (a mirror pair, an in-place idle). */
97
+ export type ClipAlign = {
98
+ offset: number;
99
+ cycles: number;
100
+ score: number;
101
+ margin: number;
102
+ };
103
+ /** What the engine measured on a clip once it was bound to this skeleton (`anim.clipInfo('Walk')`).
77
104
  * The root curves are of the clip's ROOT bone — its travel is what root motion would move. */
78
- export type ClipCurves = {
105
+ export type ClipInfo = {
79
106
  /** total horizontal root travel, metres */
80
107
  travel: number;
81
108
  /** mean root speed over the clip, m/s */
@@ -84,6 +111,17 @@ export type ClipCurves = {
84
111
  turn: number;
85
112
  /** the root barely moves — an in-place clip */
86
113
  inPlace: boolean;
114
+ /** The gait cycle fitted through the foot contacts (a foot already down at t = 0 is not a step) —
115
+ * the numbers a blend member takes as `{ offset, cycles }`. Undefined: no steps. */
116
+ cycle(): ClipCycle | undefined;
117
+ /** This loop's cycle found by POSE against `reference` (its cycle given, else `reference`'s `cycle()`,
118
+ * else offset 0 / one cycle — the answer is then relative to the reference's own time). Reads no marks:
119
+ * a markless loop (swimming, breathing, an upper-body sway) gets a cycle, and a marked one gets a
120
+ * second opinion — a mirrored anchor shows as a 0.5 disagreement with `cycle()`. Undefined: nothing to compare. */
121
+ alignTo(reference: string | number, cycle?: {
122
+ offset: number;
123
+ cycles: number;
124
+ }): ClipAlign | undefined;
87
125
  /** the clip has a gait cycle (feet planting in turn) — `phaseAt` is meaningful */
88
126
  hasPhase: boolean;
89
127
  /** When each foot TOUCHES the ground, seconds — the phase anchor. `still` is the window inside it
@@ -126,6 +164,12 @@ export type ClipCurves = {
126
164
  turnAt(time: number): number;
127
165
  /** the root's own speed at `time`, m/s — how fast the clip is moving the body right there */
128
166
  speedAt(time: number): number;
167
+ /** the PELVIS' yaw relative to the clip's heading at `time` (rad, + = left, wrapped to ±π): the stance twist
168
+ * the heading leaves out — an idle stands ~43° off the course it starts along, a stop's tail turns into that
169
+ * stance while the heading holds. A controller that switches clips mid-pose can keep the PELVIS continuous
170
+ * (turn the node by the difference between the two clips' values) where keeping the course would swing
171
+ * the body. Without a baked heading: the pelvis' yaw at frame 0 throughout. */
172
+ pelvisYawAt(time: number): number;
129
173
  /** the unit travel direction at `time` ([x, z], model space, held through stills) — integrate
130
174
  * direction × d(travel) to reconstruct the root's 2D path (a treadmill display, a turn's arc) */
131
175
  directionAt(time: number): [number, number];
@@ -185,7 +229,7 @@ export type ClipCurves = {
185
229
  * relative to the root, no turn). Starts, stops and turns are not. */
186
230
  cyclic: boolean;
187
231
  };
188
- /** The calibrated knee hinge-axis report (`anim.kneeAxis('left')`): the axis in the thigh's local
232
+ /** The calibrated knee hinge-axis report (`anim.feet.kneeAxis('left')`): the axis in the thigh's local
189
233
  * frame, and the calibration's own confidence — the angular spread of its measurements (radians;
190
234
  * a real knee comes in at a few degrees) over `samples` consecutive-frame deltas of the pack.
191
235
  * `plant` = the calibrated PLANT HEIGHTS (model space): where the ankle / toe actually sit under
@@ -309,7 +353,7 @@ export declare class Core {
309
353
  /** A bound clip's current playhead, seconds (-1 = not bound). */
310
354
  timeOf(ref: string | number): number;
311
355
  /** What the engine measured on the clip once it was bound to this skeleton — binds it if needed. */
312
- curves(ref: string | number): ClipCurves | undefined;
356
+ clipInfo(ref: string | number): ClipInfo | undefined;
313
357
  /** The skeleton's calibrated knee hinge axis for a side, with its confidence report — measured once
314
358
  * over every bound clip's knee rotation track. Undefined = no leg chain / no knee motion bound. */
315
359
  kneeAxis(side: "left" | "right"): KneeAxisReport | undefined;
@@ -321,7 +365,7 @@ export declare class Core {
321
365
  * own lateral axis — a slope's foot rotation; `slope` (degrees, + = ascending) is the INVISIBLE
322
366
  * STAIRCASE: foot heights follow the incline (leading foot higher) and the feet auto-pitch by
323
367
  * the same angle — pair it with raising the character by tan(slope) × the stride-scaled clip
324
- * travel (`curves(clip).travelAt`), which holds every planted foot's world height constant on
368
+ * travel (`clipInfo(clip).travelAt`), which holds every planted foot's world height constant on
325
369
  * its own tread. Solved in the calibrated knee hinge plane with a SOFT reach (a leg at its limit
326
370
  * keeps a residual knee bend instead of popping against the clamp), and whenever a leg would
327
371
  * overreach — a descent, a long stride — the pelvis lowers by exactly the excess (weighted by
@@ -1,5 +1,4 @@
1
1
  import type { Scene } from "./Scene";
2
2
  export declare const glState: {
3
3
  activeScene: Scene | null;
4
- frame: number;
5
4
  };
@@ -23,6 +23,10 @@ export { WebSocket } from "./runtime/net";
23
23
  export { Net, NetPlayer, Replicated, NetEntity, type NetMessage, type NetRole, type NetStatus, type NetEvents, type NetLaunch, type NetInput, type NetKind, type NetTransform } from "./net";
24
24
  export { __rpc, __channel, __serverOnly, RpcError, type ClientChannel } from "./runtime/rpc";
25
25
  export { AudioPlayer, VideoPlayer } from "./runtime/media";
26
+ export { Sound, type SoundOptions } from "./audio/Sound";
27
+ export { Voice, type VoiceEvents } from "./audio/Voice";
28
+ export { Bus, REVERB_PRESETS, type ReverbPreset, type ReverbParams, type EchoParams } from "./audio/Bus";
29
+ export { audio, type PlaySoundOptions, type SpatialOptions, type Rolloff, type AudioStats } from "./audio/audio";
26
30
  export { openFilePicker, files, type FileData } from "./runtime/files";
27
31
  export { share } from "./runtime/share";
28
32
  export { ClickEvent, TouchStartEvent, LongPressEvent } from "./runtime/touch";
@@ -60,6 +64,7 @@ export { easeIn, easeOut, easeInOut } from "./animate/easings";
60
64
  export { QRScanner } from "./plugins/qr";
61
65
  export { CameraView, type CameraFacing } from "./plugins/camera";
62
66
  export { Geolocation, type GeoPosition, type GeoOptions, type GeoWatch } from "./plugins/geolocation";
67
+ export { MapView, type MapOptions, type MapStyle, type MapStyleName, type MapCamera, type MapTap, type LngLat, type CameraMove, type FitOptions, type MapPaddingValues, type MarkerItem, type MarkerTap, type MarkerLayer, type MarkerLayerOptions, type LineLayer, type LineLayerOptions, type UserLocationOptions, } from "./plugins/map";
63
68
  export { Push, type PushPayload, type PushStatus, type PushRegisterOptions, type PushEvent } from "./plugins/push";
64
69
  export { OAuth, type OAuthCredential, type OAuthProviderName } from "./plugins/oauth";
65
70
  export { Service } from "./plugins/service";
@@ -83,6 +88,9 @@ export { Model } from "./gl/Model";
83
88
  export { Shape } from "./gl/Shape";
84
89
  export { Physics } from "./gl/Physics";
85
90
  export { Trigger } from "./gl/Trigger";
91
+ export { AudioSource, type AudioCone } from "./gl/AudioSource";
92
+ export { AudioZone } from "./gl/AudioZone";
93
+ export { SceneAudio } from "./gl/SceneAudio";
86
94
  export { CharacterController } from "./gl/CharacterController";
87
95
  export { Vehicle } from "./gl/Vehicle";
88
96
  export type { DriveLayout, DifferentialMode, EngineConfig, SteeringConfig, AeroConfig } from "./gl/Vehicle";
@@ -94,11 +102,15 @@ export { Gearbox } from "./gl/Gearbox";
94
102
  export { AnimationClip } from "./gl/animation/AnimationClip";
95
103
  export type { ClipDef, ClipTrackDef, ClipKey } from "./gl/animation/AnimationClip";
96
104
  export { Animator } from "./gl/animation/Animator";
97
- export type { WarpOptions, FeetOptions, FootState } from "./gl/animation/Animator";
105
+ export type { LodMode } from "./gl/animation/Animator";
106
+ export { Feet } from "./gl/animation/Feet";
107
+ export type { FeetOptions, FootState } from "./gl/animation/Feet";
108
+ export { Warp } from "./gl/animation/Warp";
109
+ export type { WarpOptions, StepWarpOptions } from "./gl/animation/Warp";
98
110
  export { Playback } from "./gl/animation/Playback";
99
111
  export { Loop } from "./gl/animation/Loop";
100
112
  export { Layer } from "./gl/animation/Layer";
101
- export type { PlayOptions, StopOptions, LayerOptions, LoopOptions, LoopDef, BlendPosition, ActiveClip } from "./gl/animation/core";
113
+ export type { PlayOptions, StopOptions, LayerOptions, LoopOptions, LoopDef, BlendPosition, BlendMember, ActiveClip, ClipInfo, ClipCycle, ClipAlign, KneeAxisReport, StepHandler, ClipEventHandler } from "./gl/animation/core";
102
114
  export { IK } from "./gl/IK";
103
115
  export type { IKTwoBone, IKLookAt } from "./gl/IK";
104
116
  export { Light } from "./gl/Light";
@@ -116,8 +128,11 @@ export { Geometry } from "./gl/Geometry";
116
128
  export { InstancedMesh } from "./gl/InstancedMesh";
117
129
  export type { InstanceTransform } from "./gl/InstancedMesh";
118
130
  export { Texture } from "./gl/Texture";
131
+ export type { TextureLoadOptions } from "./gl/Texture";
119
132
  export { Camera } from "./gl/Camera";
120
133
  export { Ray } from "./gl/Ray";
121
134
  export { Plane } from "./gl/Plane";
122
135
  export { Noise } from "./gl/Noise";
123
136
  export { Particles, Trail, curve, colorCurve } from "./gl/Particles";
137
+ export { DecalSet } from "./gl/DecalSet";
138
+ export type { DecalOptions, DecalSetOptions, DecalSpawnOptions, DecalPlacement } from "./gl/DecalSet";
@@ -0,0 +1,174 @@
1
+ import { NativeView } from "../ui/NativeView";
2
+ import type { FetchResponse } from "../runtime/fetch";
3
+ /** The ready-made styles a map falls back on — [OpenFreeMap](https://openfreemap.org): OSM data,
4
+ * no key, no registration, no request limits, commercial use allowed, and the whole stack is
5
+ * open-source if you'd rather self-host. `liberty` is the default. Credit them (and OSM) in your
6
+ * app: "© OpenFreeMap © OpenMapTiles, data from OpenStreetMap". A public free instance is a
7
+ * donation-funded service with no SLA — for a product with real traffic, run your own tiles and
8
+ * pass that style's URL instead. */
9
+ export type MapStyleName = "liberty" | "bright" | "positron" | "dark" | "fiord";
10
+ /**
11
+ * Where the map's style comes from:
12
+ *
13
+ * - a **name** — `"liberty"` (the default), `"positron"`, … see {@link MapStyleName}: a ready-made
14
+ * style on a free public tile server, so `MapView()` alone already draws a world map;
15
+ * - a **URL** — `"https://tiles.example.com/styles/city/style.json"`, the map fetches it;
16
+ * - a **bundled style** — `asset("./map/style.json")`: the file ships inside the app and the
17
+ * wrapper hands its text to the map, so the style itself needs no server (tiles, sprites and
18
+ * glyphs are still fetched from whatever urls it names);
19
+ * - an **already-read file** — a `FetchResponse` from `fetchLocal("style.json")` or
20
+ * `await fetch(url)` (a style downloaded once and cached in `files`);
21
+ * - the **style object** itself — the natural way to substitute a tile-server address at runtime:
22
+ * `{ ...style, sources: { openmaptiles: { type: "vector", url: `${server}/data/v3.json` } } }`.
23
+ *
24
+ * Whichever form: **every url INSIDE the style (`sources[].url`, `sprite`, `glyphs`) must be
25
+ * absolute.** maplibre-native, unlike maplibre-gl-js, resolves no relative ones — a style with
26
+ * them loads to an empty basemap (your layers still draw). A tileserver-gl instance emits
27
+ * relative urls until its `publicUrl` is configured.
28
+ */
29
+ export type MapStyle = MapStyleName | (string & {}) | FetchResponse | object;
30
+ /** `[longitude, latitude]` — GeoJSON order, the same as the style, the tiles and your data. */
31
+ export type LngLat = [number, number];
32
+ export interface MapCamera {
33
+ center: LngLat;
34
+ zoom: number;
35
+ /** Degrees clockwise from north. */
36
+ bearing: number;
37
+ /** Degrees from the vertical. */
38
+ pitch: number;
39
+ }
40
+ export interface MapOptions {
41
+ /** The MapLibre style: a ready-made name (`"liberty"` — the default, `"positron"`, …), a URL,
42
+ * a style bundled with the app (`asset("./style.json")`), an already-read file
43
+ * (`fetchLocal("style.json")`, `await fetch(url)`) or the style object itself — see
44
+ * {@link MapStyle}. */
45
+ style?: MapStyle;
46
+ center?: LngLat;
47
+ zoom?: number;
48
+ minZoom?: number;
49
+ maxZoom?: number;
50
+ bearing?: number;
51
+ pitch?: number;
52
+ /** Two-finger rotate gesture (default true). */
53
+ rotate?: boolean;
54
+ /** Two-finger tilt gesture (default false — most city maps stay flat). */
55
+ tilt?: boolean;
56
+ }
57
+ /** A tap on the map itself — not on a feature of a managed layer. */
58
+ export interface MapTap {
59
+ lngLat: LngLat;
60
+ /** View-space point, px. */
61
+ point: [number, number];
62
+ }
63
+ export interface CameraMove {
64
+ zoom?: number;
65
+ bearing?: number;
66
+ pitch?: number;
67
+ /** Animation length, ms (flyTo only; default 600). */
68
+ duration?: number;
69
+ }
70
+ export interface MapPaddingValues {
71
+ top?: number | string;
72
+ left?: number | string;
73
+ bottom?: number | string;
74
+ right?: number | string;
75
+ }
76
+ export interface FitOptions {
77
+ /** Px around the points, or per edge. Added to the view padding set by `setPadding`. */
78
+ padding?: number | MapPaddingValues;
79
+ maxZoom?: number;
80
+ /** Default true. */
81
+ animate?: boolean;
82
+ }
83
+ /** One marker. `id` comes back in `onTap`; `icon` names an image of the style's sprite; `color` /
84
+ * `title` feed the default layers; extra keys become feature properties. */
85
+ export interface MarkerItem {
86
+ id: string | number;
87
+ lngLat: LngLat;
88
+ icon?: string;
89
+ color?: string;
90
+ title?: string;
91
+ [property: string]: any;
92
+ }
93
+ export interface MarkerTap {
94
+ id: string | number;
95
+ lngLat: LngLat;
96
+ /** Every property of the tapped feature (the item's keys, `id` and `lngLat` excluded). */
97
+ properties: Record<string, any>;
98
+ }
99
+ export interface MarkerLayerOptions {
100
+ /** Group nearby markers into clusters (a cluster tap zooms in). Default false. */
101
+ cluster?: boolean;
102
+ /** Cluster radius, px (default 50). */
103
+ clusterRadius?: number;
104
+ /** Zoom at which clusters stop forming (default: maxZoom − 1). */
105
+ clusterMaxZoom?: number;
106
+ }
107
+ export interface LineLayerOptions {
108
+ color?: string;
109
+ /** Px (default 4). */
110
+ width?: number;
111
+ /** 0–1 (default 1). */
112
+ opacity?: number;
113
+ }
114
+ export interface UserLocationOptions {
115
+ /** Horizontal accuracy radius, meters — drawn as the halo around the dot. */
116
+ accuracy?: number | null;
117
+ /** Degrees clockwise from north — drawn as the direction wedge; null hides it. */
118
+ heading?: number | null;
119
+ }
120
+ export interface MarkerLayer {
121
+ readonly name: string;
122
+ /** Replace the layer's markers. */
123
+ set(items: MarkerItem[]): this;
124
+ clear(): this;
125
+ /** A marker (or any feature of this layer's source) was tapped. */
126
+ onTap(callback: (marker: MarkerTap) => void): this;
127
+ }
128
+ export interface LineLayer {
129
+ readonly name: string;
130
+ /** Replace the line with these vertices. */
131
+ set(coordinates: LngLat[]): this;
132
+ clear(): this;
133
+ }
134
+ export interface MapView extends NativeView {
135
+ /** The style loaded and the map is interactive (queued calls have been replayed). */
136
+ onReady(callback: () => void): this;
137
+ /** A tap that hit no feature of a managed layer. */
138
+ onTap(callback: (tap: MapTap) => void): this;
139
+ /** The camera settled after a gesture or an animation. */
140
+ onMove(callback: (camera: MapCamera) => void): this;
141
+ /** The map reported a problem — a style that wouldn't load, a source it couldn't reach. Never
142
+ * fatal; with no handler the message goes to `console.error`, so it is never silent. */
143
+ onError(callback: (error: {
144
+ message: string;
145
+ }) => void): this;
146
+ /** A named marker layer (one GeoJSON source). If the style already declares a source with this
147
+ * name, its layers are used as-is and only the data is pushed; otherwise the plugin creates the
148
+ * source and default marker layers (colored dot, `icon`, `title` label; clusters on request). */
149
+ markers(name: string, options?: MarkerLayerOptions): MarkerLayer;
150
+ /** A named line layer (one GeoJSON source) — same style-first rule as `markers`. */
151
+ line(name: string, options?: LineLayerOptions): LineLayer;
152
+ /** Raw escape hatch: replace the data of any GeoJSON source in the style. */
153
+ setData(source: string, geojson: object): this;
154
+ flyTo(center: LngLat, options?: CameraMove): this;
155
+ jumpTo(center: LngLat, options?: CameraMove): this;
156
+ /** Fit the camera to these points (padding + the view padding respected). */
157
+ fitPoints(points: LngLat[], options?: FitOptions): this;
158
+ /** Content inset: the part of the view covered by your UI (`"40%"` = of the view's size).
159
+ * Camera operations center inside the remaining area. */
160
+ setPadding(padding: MapPaddingValues): this;
161
+ getCamera(): Promise<MapCamera>;
162
+ /** Move the user puck (the map draws it; the position comes from you — `Geolocation.watch`).
163
+ * `null` hides it. */
164
+ setUserLocation(lngLat: LngLat | null, options?: UserLocationOptions): this;
165
+ }
166
+ /**
167
+ * Create a map view. `MapView.isSupported` reports whether this host registered a "map" view —
168
+ * check it before offering the feature (web, headless and shells without the plugin have none).
169
+ */
170
+ export declare const MapView: {
171
+ (options?: MapOptions): MapView;
172
+ /** Whether this host registered a "map" view. */
173
+ readonly isSupported: boolean;
174
+ };
@@ -8,6 +8,7 @@ export declare const InputChannel: {
8
8
  readonly WheelY: 5;
9
9
  readonly PointerLocked: 6;
10
10
  readonly GamepadCount: 7;
11
+ readonly PointerOnUI: 8;
11
12
  readonly GamepadBase: 16;
12
13
  readonly GamepadStride: 16;
13
14
  readonly PadConnected: 0;
@@ -64,6 +65,11 @@ export declare const mouse: {
64
65
  * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and
65
66
  * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */
66
67
  readonly locked: boolean;
68
+ /** The primary button went down on a UI element (a button, a scrollable, an input, a modal
69
+ * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so
70
+ * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.
71
+ * Always false while `locked`. A press that fell through to the scene reads false. */
72
+ readonly onUI: boolean;
67
73
  lock(): boolean;
68
74
  unlock(): void;
69
75
  };
@@ -108,6 +114,11 @@ export declare const Input: {
108
114
  * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and
109
115
  * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */
110
116
  readonly locked: boolean;
117
+ /** The primary button went down on a UI element (a button, a scrollable, an input, a modal
118
+ * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so
119
+ * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.
120
+ * Always false while `locked`. A press that fell through to the scene reads false. */
121
+ readonly onUI: boolean;
111
122
  lock(): boolean;
112
123
  unlock(): void;
113
124
  };
@@ -2,6 +2,7 @@ import type { FetchResponse } from "../runtime/fetch";
2
2
  import type { SvgSourceValue as SvgSource } from "../runtime/misc";
3
3
  import type { File } from "../runtime/fetch";
4
4
  import { Canvas } from "../canvas/Canvas";
5
+ import type { Scene2D } from "../g2/Scene2D";
5
6
  import { type Color, type ElementStyle, type UIElementBase } from "./UINode";
6
7
  export type UIImageStyle = ElementStyle & {
7
8
  borderRadius?: number;
@@ -13,12 +14,21 @@ export type UIImageStyle = ElementStyle & {
13
14
  export type CanvasImageSource = {
14
15
  canvasSurface: number;
15
16
  };
16
- /** Accepted image sources. A Canvas is baked to a surface marker on assign. */
17
- export type ImageSource = string | FetchResponse | File | SvgSource | Canvas;
18
- /** The stored/resolved image source (a Canvas is resolved to a surface marker). */
19
- export type ResolvedImageSource = string | FetchResponse | File | SvgSource | CanvasImageSource;
17
+ /** A live 2D scene as an image source: the host draws the scene into the node's box every frame
18
+ * (the scene's camera, projected into the box). No intrinsic size — give the node a width and
19
+ * height. */
20
+ export type Scene2DImageSource = {
21
+ scene2d: number;
22
+ };
23
+ /** Accepted image sources. A Canvas is baked to a surface marker on assign; a Scene2D becomes a
24
+ * live-scene marker. */
25
+ export type ImageSource = string | FetchResponse | File | SvgSource | Canvas | Scene2D;
26
+ /** The stored/resolved image source (a Canvas is resolved to a surface marker, a Scene2D to a
27
+ * live-scene marker). */
28
+ export type ResolvedImageSource = string | FetchResponse | File | SvgSource | CanvasImageSource | Scene2DImageSource;
20
29
  /** An image element. Sources: URL / `asset(...)`, fetch response / File, an SVG source
21
- * (`assetIcon`), or a live Canvas (`canvas.update()` refreshes the node in place). */
30
+ * (`assetIcon`), a live Canvas (`canvas.update()` refreshes the node in place), or a live Scene2D
31
+ * (drawn into the box every frame — a minimap). */
22
32
  export interface UIImage extends UIElementBase<UIImageStyle> {
23
33
  readonly type: "image";
24
34
  /** The image source — writable to swap the picture in place. */