lecodes-sdk 1.1.0 → 1.2.0

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.
@@ -22,6 +22,9 @@ export type SunOptions = {
22
22
  * 3 - 2048 map, contact-hardening soft edges (PCSS: sharp where the caster touches, softer
23
23
  * away; discrete-GPU territory, ~+60 % of a frame on an iGPU)
24
24
  * A lightmapped level already carries every static shadow, so 0 is a legitimate choice there.
25
+ * On a level with a baked light grid the variance / PCSS filters cannot be used (they need every
26
+ * receiver in the shadow map, and the baked statics are kept out of it): 3 renders as PCSS on the
27
+ * depth map - the same contact-hardening look - and 2 renders as 1.
25
28
  */
26
29
  shadowsQuality?: 0 | 1 | 2 | 3;
27
30
  /**
@@ -184,6 +184,15 @@ export type ParticlesOptions = ParticlesMaterialOptions & {
184
184
  * without this the engine picks who covers whom per frame (smoke popping over a fireball).
185
185
  * Default 0; a fireball wants 2, its smoke 1, a smoke trail -1. */
186
186
  order?: number;
187
+ /** Sprites take the light of the PLACE each one is in — the level's baked light grid (`env.lightmap.volume`).
188
+ * A sprite is unlit: its colour is the picture, which is right for fire and wrong for dust — a puff kicked up
189
+ * under an awning glows as if it stood in the sun. With `lit` every particle's colour is multiplied by the light
190
+ * where it is, relative to the level's OPEN ground: exactly the authored colour out in the sun, the ambient's
191
+ * share of it (tinted the way the shade is) under a roof — per particle, so a trail of puffs laid from the sun
192
+ * into the shade is lit along its length. Author the colour for the open; nothing else to tune. Without a grid
193
+ * — a level with no bake, a host that has none — the colours are drawn as authored. Points, quads, stretch and
194
+ * `Trail`; mesh particles are lit by their material. Default false. */
195
+ lit?: boolean;
187
196
  /** Coarse draw order among ALL blended draws, 0 (first) … 7 (last) — see `Mesh.renderPriority`.
188
197
  * Default 5: meshes sit at 4 and decals at 3, so smoke covers a car's glass and its skid marks
189
198
  * whatever the camera does (the engine's depth sort compares object centres, and an emitter's
@@ -234,6 +243,8 @@ export declare class Particles extends Node {
234
243
  /** Lay a frame's spawns along a curve through the emitter's path, not the straight chord. */
235
244
  set smooth(val: boolean);
236
245
  set order(val: number);
246
+ /** Colours × the baked light where each particle is — see `ParticlesOptions.lit`. */
247
+ set lit(val: boolean);
237
248
  /** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */
238
249
  set renderPriority(v: number);
239
250
  set velocityOverLife(v: VelocityOverLife);
@@ -279,6 +290,9 @@ export type TrailOptions = Omit<ParticlesMaterialOptions, "render" | "stretch">
279
290
  * frame rate, since a longer frame bows further off its own chord. Default false; see
280
291
  * `ParticlesOptions.smooth`. */
281
292
  smooth?: boolean;
293
+ /** The strip takes the baked light of the place each of its points is at — `ParticlesOptions.lit`. Smoke and
294
+ * dust trails; leave it off for a glowing one. Default false. */
295
+ lit?: boolean;
282
296
  /** Which way the strip's WIDTH points.
283
297
  *
284
298
  * `'camera'` (default) rolls the strip about its own length to stay flat to the viewer — it can
@@ -317,6 +331,7 @@ export declare class Trail extends Node {
317
331
  set minDistance(val: number);
318
332
  /** Follow a curve through the emitter's path instead of the straight chord between frames. */
319
333
  set smooth(val: boolean);
334
+ set lit(val: boolean);
320
335
  /** Which way the strip's width points — see `TrailOptions.orient`. Keeps the current `faceCamera`. */
321
336
  set orient(val: "camera" | "x" | "y" | "z");
322
337
  /** The hybrid's floor — see `TrailOptions.faceCamera`. */
@@ -6,8 +6,9 @@ import type { WarpOptions } from "./Warp";
6
6
  import type { Node } from "../Node";
7
7
  /** How fast the character wants to go: the gait picks its clips and its speed. */
8
8
  export type Gait = "walk" | "run" | "sprint";
9
- /** What the engine shows: the idle, a start, the gait loop, a turn while moving, a stop, or a turn on the spot. */
10
- export type LocomotionState = "idle" | "start" | "move" | "turn" | "stop" | "spin";
9
+ /** What the engine shows: the idle, a start, the gait loop, a turn while moving, a stop, a turn on the spot —
10
+ * an ACTION (`act()`): a one-shot that owns the body until it hands over — or the STRAFE blend (`move({ strafe })`). */
11
+ export type LocomotionState = "idle" | "start" | "move" | "turn" | "stop" | "spin" | "action" | "strafe";
11
12
  /** Who moves the body:
12
13
  * `'hybrid'` (the default) — the clip's own recorded motion moves it; while the gait loop shows it
13
14
  * is ADJUSTED toward what the simulation wants by at most `tuning.adjust` metres a second, and a
@@ -42,6 +43,10 @@ export type LocomotionSet = {
42
43
  turns?: LocomotionClip[];
43
44
  /** turns on the spot — what a facing still owed by a standing body plays */
44
45
  spins?: LocomotionClip[];
46
+ /** the STRAFE set: the same gait recorded forward, backward, to either side and on the diagonals — the members of
47
+ * the directional blend `move(dir, { face, strafe: true })` shows. `angle` = the way a take travels in the body's
48
+ * frame (degrees, + = left); left out, the engine reads it off the take's root. */
49
+ strafes?: LocomotionClip[];
45
50
  };
46
51
  /** The tuning. Times are seconds, speeds m/s, angles degrees. */
47
52
  export type LocomotionTuning = {
@@ -199,6 +204,8 @@ export declare class Locomotion extends Aspect<"loco", Node, LocomotionEvents> {
199
204
  private _mag;
200
205
  private _gait;
201
206
  private _seq;
207
+ private _act;
208
+ private _strafe;
202
209
  private readonly _in;
203
210
  private readonly _out;
204
211
  private readonly _names;
@@ -225,11 +232,53 @@ export declare class Locomotion extends Aspect<"loco", Node, LocomotionEvents> {
225
232
  /** State the movement intent for this frame: a world direction (its length is the stick's pull,
226
233
  * clamped to 1) and the gait. `null` = no movement — the body stops, but it keeps facing where it
227
234
  * was last asked to, and turns there on the spot if it still owes the turn.
228
- * `face` states a facing of its own (aiming, strafing, a camera-relative shooter). */
235
+ * `face` states a facing of its own (aiming, a camera-relative shooter) — and with `strafe: true` the body MOVES
236
+ * where the direction points while it faces there: the loop becomes the directional blend of `set.strafes` (a
237
+ * guard, a lock-on), the facing is steered standing too, state `'strafe'`. Stated every frame like the rest. */
229
238
  move(direction: Vec3Like | null | undefined, options?: {
230
239
  gait?: Gait;
231
240
  face?: Vec3Like;
241
+ strafe?: boolean;
232
242
  }): void;
243
+ /** Play an ACTION: a one-shot that OWNS the body the way a start or a stop does — a roll, a backstep, a lunging
244
+ * attack. Its recording moves the body alone (in every displacement mode but `'data'`, where the host does),
245
+ * the steering and the selector stand by, and when it hands over the usual rules carry on: a direction held
246
+ * starts (or, still carrying speed, runs on), nothing held stands.
247
+ *
248
+ * `direction` is where its TRAVEL must go, world (`Vec3`, or a heading in degrees, 0 = +Z, + = toward +X). A
249
+ * clip travels some way relative to the body — forward, left, back; measured off its own root, or `angle`
250
+ * (degrees, + = left) — and the body is turned by what is left between that and `direction`, over `turn`
251
+ * seconds (default 0.12), so the travel lands exactly where it was pointed. Which clip to play is yours to
252
+ * pick: the one whose travel is nearest the direction IN THE BODY'S FRAME (`direction − facing`) leaves the
253
+ * least to turn. Left out = it plays where the body faces.
254
+ *
255
+ * `at` enters the clip that many seconds in (a wind-up skipped), `rate` plays it faster or slower (its metres
256
+ * stay, the time changes), `travel` takes only that share of its recorded travel (an attack aimed at a target:
257
+ * 0.3 to stop at the blade's length from one that is close, 1.3 to reach one a step too far — the pose is
258
+ * untouched, so keep it to a fast step; `{ share, at, after }` takes another share from clip time `at` on: a
259
+ * swing's take travels on after its cut, into a body that stands at the blade's length), `fade` is the transition into it and `out` the one out of it (default: the tuning's
260
+ * `blend`; an action ends in ITS stance, not the idle's, and a longer way out is what hides that), and `exit` is the
261
+ * clip time from which a MOVE intent may take over — the cancel window: along the way the body faces at once, a
262
+ * heading that needs a turn as soon as the body has slowed to where a start can answer; with nothing asked for it plays out, to
263
+ * its end (an action ends in its own recovery, at rest), and the body then STANDS THE WAY THE ACTION LEFT IT:
264
+ * the facing intent that outlives a released key is not a demand after an action — no turn on the spot.
265
+ * WHEN an action may be asked for (out of another one, out of a start) is the caller's rule: this cuts into
266
+ * whatever shows. `state` reads `'action'` while it does. False = no such clip. */
267
+ act(clip: string, options?: {
268
+ direction?: Vec3Like | number;
269
+ angle?: number;
270
+ turn?: number;
271
+ at?: number;
272
+ exit?: number;
273
+ fade?: number;
274
+ out?: number;
275
+ rate?: number;
276
+ travel?: number | {
277
+ share: number;
278
+ at: number;
279
+ after: number;
280
+ };
281
+ }): boolean;
233
282
  /** Face this way without moving — the facing intent on its own (`Vec3`, or a heading in degrees,
234
283
  * 0 = +Z, + = toward +X). A standing body turns to it on the spot. */
235
284
  face(direction: Vec3Like | number): void;
@@ -176,6 +176,14 @@ export declare class Terrain {
176
176
  heightAt(x: number, z: number): number;
177
177
  /** The drawn triangle's normal at a local (x, z) (unit Vec3, +Y up). */
178
178
  normalAt(x: number, z: number): Vec3;
179
+ /** The LAYER WEIGHTS at a local (x, z) — what the splat shader blends there: the control map read bilinearly
180
+ * between its samples and normalised to sum 1 (`[1, 0, 0, 0]` where the map is empty, as the shader has
181
+ * it). Index = the layer's in `layers`. Outside the grid the edge answers. This is how a game asks WHAT the
182
+ * ground is under a point — footprints in the sand and none on the cobble, a footstep sound per layer, dust
183
+ * by surface — and the blend is already in the numbers, so a transition is a fade and not a line. */
184
+ weightsAt(x: number, z: number): [number, number, number, number];
185
+ /** The heaviest layer's index at a local (x, z) — `weightsAt` when only "which one" is asked. */
186
+ layerAt(x: number, z: number): number;
179
187
  /** The smooth (vertex) normal at integer sample (ix, iz). */
180
188
  sampleNormal(ix: number, iz: number): Vec3;
181
189
  /** Extent in local metres: `[width, depth]`. */
@@ -82,6 +82,13 @@ export interface GamepadState {
82
82
  axis(name: GamepadAxisName, deadzone?: number): number;
83
83
  /** Held? Same as `Input.key(code, index)`. */
84
84
  button(code: string): boolean;
85
+ /** Rumble: `strong` = the heavy low-frequency motor, `weak` = the light high-frequency one, both
86
+ * 0..1, for `durationMs` (default 200, hosts cap at 5000). A new call replaces the running
87
+ * effect. The host stops the motors by itself — after the duration, on focus loss and when the
88
+ * project is swapped — so there is nothing to clean up. False when the pad or host has no motors. */
89
+ rumble(strong: number, weak?: number, durationMs?: number): boolean;
90
+ /** Stop the running rumble now. */
91
+ stopRumble(): void;
85
92
  }
86
93
  export declare const Input: {
87
94
  /**