lecodes-sdk 1.0.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.
- package/dist/global.d.ts +18 -4
- package/dist/inject.js +260 -361
- package/dist/types/animate/tween/Animation.d.ts +69 -0
- package/dist/types/animate/tween/Timeline.d.ts +55 -0
- package/dist/types/animate/tween/animateValue.d.ts +27 -0
- package/dist/types/animate/tween/easing.d.ts +29 -0
- package/dist/types/animate/tween/spec.d.ts +178 -0
- package/dist/types/g2/Node2D.d.ts +16 -0
- package/dist/types/g2/Sprite.d.ts +11 -1
- package/dist/types/gl/Camera.d.ts +15 -1
- package/dist/types/gl/Foliage.d.ts +47 -0
- package/dist/types/gl/Geometry.d.ts +24 -0
- package/dist/types/gl/Light.d.ts +28 -7
- package/dist/types/gl/Lightmap.d.ts +90 -60
- package/dist/types/gl/Material.d.ts +28 -20
- package/dist/types/gl/Model.d.ts +7 -5
- package/dist/types/gl/Node.d.ts +18 -0
- package/dist/types/gl/Particles.d.ts +55 -1
- package/dist/types/gl/Scene.d.ts +20 -0
- package/dist/types/gl/animation/AnimationClip.d.ts +19 -0
- package/dist/types/gl/animation/Animator.d.ts +27 -0
- package/dist/types/gl/animation/DynamicBone.d.ts +19 -8
- package/dist/types/gl/animation/IK.d.ts +86 -30
- package/dist/types/gl/animation/Locomotion.d.ts +52 -3
- package/dist/types/gl/animation/Warp.d.ts +2 -1
- package/dist/types/gl/animation/core.d.ts +35 -4
- package/dist/types/gl/physics/Ragdoll.d.ts +87 -12
- package/dist/types/gl/terrain/Terrain.d.ts +12 -2
- package/dist/types/inject.d.ts +8 -2
- package/dist/types/runtime/input.d.ts +7 -0
- package/dist/types/scene/defineScene.d.ts +44 -32
- package/dist/types/ui/UIButton.d.ts +3 -1
- package/dist/types/ui/UIInput.d.ts +5 -1
- package/dist/types/ui/UINode.d.ts +24 -24
- package/dist/types.json +1 -1
- package/package.json +1 -1
- package/prompts/README.md +142 -142
- package/prompts/core-design.md +27 -4
- package/prompts/core.md +35 -6
- package/prompts/dist/2d-game.md +197 -408
- package/prompts/dist/3d-app.md +166 -491
- package/prompts/dist/ar-app.md +163 -373
- package/prompts/dist/design.md +87 -83
- package/prompts/dist/ui-app.md +136 -325
- package/prompts/select.ts +19 -4
- package/src/animate/tween/Animation.ts +378 -0
- package/src/animate/tween/Timeline.ts +175 -0
- package/src/animate/tween/animateValue.ts +100 -0
- package/src/animate/tween/easing.ts +172 -0
- package/src/animate/tween/spec.ts +479 -0
- package/src/audio/audio.ts +161 -161
- package/src/bridges.d.ts +235 -65
- package/src/compile/__tests__/assetMacro.test.ts +26 -0
- package/src/compile/__tests__/detectEntry.test.ts +19 -0
- package/src/compile/__tests__/serverSplit.test.ts +27 -0
- package/src/compile/bundler.ts +34 -4
- package/src/compile/compileProject.ts +31 -1
- package/src/compile/detectEntry.ts +8 -3
- package/src/compile/index.ts +2 -0
- package/src/compile/serverSplit.ts +9 -3
- package/src/g2/Node2D.ts +38 -0
- package/src/g2/Sprite.ts +20 -1
- package/src/gl/Camera.ts +34 -1
- package/src/gl/CameraPlace.ts +52 -52
- package/src/gl/Foliage.ts +102 -0
- package/src/gl/Geometry.ts +393 -348
- package/src/gl/Light.ts +49 -16
- package/src/gl/Lightmap.ts +439 -275
- package/src/gl/Material.ts +59 -47
- package/src/gl/Mesh.ts +120 -120
- package/src/gl/Model.ts +23 -12
- package/src/gl/Node.ts +39 -0
- package/src/gl/Particles.ts +80 -2
- package/src/gl/Scene.ts +34 -1
- package/src/gl/animation/AnimationClip.ts +52 -0
- package/src/gl/animation/Animator.ts +42 -2
- package/src/gl/animation/DynamicBone.ts +35 -12
- package/src/gl/animation/IK.ts +173 -152
- package/src/gl/animation/Locomotion.ts +72 -8
- package/src/gl/animation/Playback.ts +5 -4
- package/src/gl/animation/Warp.ts +5 -2
- package/src/gl/animation/core.ts +65 -4
- package/src/gl/physics/Ragdoll.ts +451 -272
- package/src/gl/scenarios.ts +291 -291
- package/src/gl/terrain/Terrain.ts +33 -2
- package/src/inject.ts +236 -226
- package/src/runtime/input.ts +11 -0
- package/src/scene/defineScene.ts +72 -62
- package/src/scene/gizmos.ts +148 -148
- package/src/ui/UIButton.ts +2 -2
- package/src/ui/UIInput.ts +3 -3
- package/src/ui/UINode.ts +61 -36
- package/dist/types/animate/animate.d.ts +0 -20
- package/src/animate/animate.ts +0 -238
|
@@ -2,46 +2,102 @@ import { Aspect } from "../../core/Aspect";
|
|
|
2
2
|
import { type Vec3Like } from "../../math/vec";
|
|
3
3
|
import { Quat } from "../../math/quat";
|
|
4
4
|
import type { Node } from "../Node";
|
|
5
|
+
import type { Core } from "./core";
|
|
5
6
|
type Target = Node | Vec3Like;
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/** Bend hint — the mid joint is pulled toward it (Node or world position). */
|
|
14
|
-
pole?: Target;
|
|
15
|
-
/** World rotation the END bone takes after the solve — a Node (its world rotation) or a Quat.
|
|
16
|
-
* Unset = the end bone keeps its animated local rotation (a hand on a grip, a foot on a slope
|
|
17
|
-
* want it set). Blended by `weight · rotationWeight`. */
|
|
18
|
-
rotation?: Node | Quat;
|
|
19
|
-
/** 0–1 contribution of `rotation` (on top of `weight`). */
|
|
20
|
-
rotationWeight: number;
|
|
7
|
+
/** What both chains share: the native handle, the parameter push, the readback. */
|
|
8
|
+
declare abstract class Chain<Name extends string> extends Aspect<Name, Node> {
|
|
9
|
+
protected _rig?: Core;
|
|
10
|
+
protected _ik: number;
|
|
11
|
+
protected _weight: number;
|
|
12
|
+
protected _enabled: boolean;
|
|
13
|
+
protected abstract readonly kind: 0 | 1;
|
|
21
14
|
/** 0–1 contribution (blend in/out, e.g. foot planting only while grounded). */
|
|
22
|
-
weight: number;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
solve()
|
|
15
|
+
get weight(): number;
|
|
16
|
+
set weight(v: number);
|
|
17
|
+
/** Solve every frame (default). */
|
|
18
|
+
get enabled(): boolean;
|
|
19
|
+
set enabled(v: boolean);
|
|
20
|
+
/** After the last solve: how far the end bone still is from its target, metres (0 = reached). */
|
|
21
|
+
get error(): number;
|
|
22
|
+
onAttach(): void;
|
|
23
|
+
onDetach(): void;
|
|
24
|
+
onReconfigure(): void;
|
|
25
|
+
protected params(): Float32Array;
|
|
26
|
+
/** Push the description to the engine (a no-op until attached). */
|
|
27
|
+
protected abstract push(): void;
|
|
28
|
+
}
|
|
29
|
+
/** Two-bone analytic IK (limbs). Attach to the END bone: `foot.aspect(IK.TwoBone, { target })` solves
|
|
30
|
+
* upper (grandparent) + mid (parent) so the end reaches `target`; `pole` steers the bend (knee /
|
|
31
|
+
* elbow) — a Node or world point; `anchor` makes it ride a socket of the rig instead (see the file
|
|
32
|
+
* header). */
|
|
33
|
+
declare class TwoBone extends Chain<"ik"> {
|
|
34
|
+
static readonly aspect = "ik";
|
|
35
|
+
protected readonly kind: 0;
|
|
36
|
+
private _target?;
|
|
37
|
+
private _pole?;
|
|
38
|
+
private _rotation?;
|
|
39
|
+
private _rotationWeight;
|
|
40
|
+
private _anchor;
|
|
41
|
+
private _anchorTime;
|
|
42
|
+
private _anchorPin;
|
|
43
|
+
/** Where the end bone should be (a Node — read by the engine every frame — or a world position). */
|
|
44
|
+
get target(): Target | undefined;
|
|
45
|
+
set target(v: Target | undefined);
|
|
46
|
+
/** Bend hint — the mid joint is pulled toward it (a Node or a world point). */
|
|
47
|
+
get pole(): Target | undefined;
|
|
48
|
+
set pole(v: Target | undefined);
|
|
49
|
+
/** World rotation the END bone takes after the solve — a Node (its world rotation) or a Quat. Unset =
|
|
50
|
+
* the end bone keeps its animated rotation (a hand on a grip, a foot on a slope want it set). Blended
|
|
51
|
+
* by `weight · rotationWeight`. An anchored chain takes its rotation from the socket instead. */
|
|
52
|
+
get rotation(): Node | Quat | undefined;
|
|
53
|
+
set rotation(v: Node | Quat | undefined);
|
|
54
|
+
/** 0–1 contribution of `rotation` (on top of `weight`); for an anchored chain, of the socket's turn. */
|
|
55
|
+
get rotationWeight(): number;
|
|
56
|
+
set rotationWeight(v: number);
|
|
57
|
+
/** ANCHORED: the name of the LIVE socket the end bone rides (`anim.sockets(...)`) — its target and
|
|
58
|
+
* rotation come from the socket and the playing clips' anchor spans; `target` / `pole` / `rotation`
|
|
59
|
+
* are ignored. '' = a plain chain. */
|
|
60
|
+
get anchor(): string;
|
|
61
|
+
set anchor(v: string);
|
|
62
|
+
/** Anchored: how fast the hand moves between sockets — the halflife (s) of the spring the applied
|
|
63
|
+
* delta follows the wanted one with (default 0.05). */
|
|
64
|
+
get anchorTime(): number;
|
|
65
|
+
set anchorTime(v: number);
|
|
66
|
+
/** Anchored: 0..1 how hard the end bone is PINNED on its socket while the playing clips leave it there
|
|
67
|
+
* (a GAP in their spans — the hand is holding the gun). 1 = it sits exactly on the socket, so nothing
|
|
68
|
+
* in the pose below can slide it along the gun; 0 (default) = it keeps the take's own relation to the
|
|
69
|
+
* socket, moved by the delta. A clip's SPANS carry their own pin and default to 0, because a hand on
|
|
70
|
+
* its way to a magazine must keep the take's motion — so this knob is about holding, not reaching. */
|
|
71
|
+
get anchorPin(): number;
|
|
72
|
+
set anchorPin(v: number);
|
|
73
|
+
/** After the last solve: the anchor delta applied — how far (m) and how much (rad) the live socket
|
|
74
|
+
* moved the hand off the take's own pose. 0 for a plain chain. */
|
|
75
|
+
get anchorDelta(): {
|
|
76
|
+
distance: number;
|
|
77
|
+
angle: number;
|
|
78
|
+
};
|
|
79
|
+
protected push(): void;
|
|
28
80
|
}
|
|
29
81
|
/** Aim a bone at a target (head / eyes / turret). Attach to the bone itself:
|
|
30
82
|
* `head.aspect(IK.LookAt, { target: camera, limit: 70 })`. `axis` is the bone's LOCAL forward
|
|
31
83
|
* (the direction that should point at the target) — rigs differ; default −Z, Mixamo heads look
|
|
32
84
|
* along +Z of the head bone in most exports, so pass `axis: [0, 0, 1]` there if it faces backwards. */
|
|
33
|
-
declare class LookAt extends
|
|
85
|
+
declare class LookAt extends Chain<"lookAt"> {
|
|
34
86
|
static readonly aspect = "lookAt";
|
|
35
|
-
|
|
87
|
+
protected readonly kind: 1;
|
|
88
|
+
private _target?;
|
|
89
|
+
private _axis;
|
|
90
|
+
private _limit;
|
|
91
|
+
/** What to look at (a Node — read by the engine every frame — or a world position). */
|
|
92
|
+
get target(): Target | undefined;
|
|
93
|
+
set target(v: Target | undefined);
|
|
36
94
|
/** The bone's local axis that should point at the target. */
|
|
37
|
-
axis: Vec3Like;
|
|
95
|
+
get axis(): Vec3Like;
|
|
96
|
+
set axis(v: Vec3Like);
|
|
38
97
|
/** Max deflection from the animated direction, in degrees (default 80). */
|
|
39
|
-
limit: number;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
enabled: boolean;
|
|
43
|
-
update(): void;
|
|
44
|
-
solve(): void;
|
|
98
|
+
get limit(): number;
|
|
99
|
+
set limit(v: number);
|
|
100
|
+
protected push(): void;
|
|
45
101
|
}
|
|
46
102
|
/** Inverse kinematics aspects — attach to bones (see file header). */
|
|
47
103
|
export declare const IK: {
|
|
@@ -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,
|
|
10
|
-
|
|
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,
|
|
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;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
export type WarpOptions = {
|
|
3
3
|
/** Fit the stride to the speed the body actually travels at. `[min, max]` clamps the scale (default
|
|
4
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.
|
|
5
|
+
* none of this; open the range for a pack that must cover speeds it was never recorded at. The clip's
|
|
6
|
+
* own speed is its root motion — an in-place loop takes part only with a declared pace (see above). */
|
|
6
7
|
stride?: boolean | [number, number];
|
|
7
8
|
/** Turn the lower body toward where the body really travels; a number caps the turn in degrees
|
|
8
9
|
* (default 20). The whole twist lives in one joint: a few degrees read as a lean, a lot as a broken
|
|
@@ -13,15 +13,24 @@ export type PlayOptions = {
|
|
|
13
13
|
fade?: number;
|
|
14
14
|
/** Transition seconds for the way in only (overrides `fade`). */
|
|
15
15
|
fadeIn?: number;
|
|
16
|
-
/** One-shots: the transition BACK to the loop
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
/** One-shots: the transition BACK to the loop after the end (overrides `fade`; `0` = cut at the end).
|
|
17
|
+
* The clip plays to its last frame; the loop then takes over and the difference between the two poses
|
|
18
|
+
* (and their velocities) decays over this time, so no part of the clip is cut — to play less of it,
|
|
19
|
+
* give it an `end`. On a layer with no loop the clip HOLDS its last frame (a rock that broke stays
|
|
20
|
+
* broken) — `anim.stop({ fade })` is the way back to rest. */
|
|
20
21
|
fadeOut?: number;
|
|
21
22
|
/** Playback rate for this clip (default 1). */
|
|
22
23
|
speed?: number;
|
|
23
24
|
/** Rewind even if the clip is already playing (default: rewind only if it isn't). */
|
|
24
25
|
restart?: boolean;
|
|
26
|
+
/** Play a WINDOW of the clip, seconds of the clip: enter at `start` (default 0; only when the play
|
|
27
|
+
* rewinds — see `restart`) and treat `end` (default the clip's end) as the end — the hand-over fires
|
|
28
|
+
* there, the last frame held there, events beyond it never fire. Only the swing of a longer take, the
|
|
29
|
+
* wind-up without the recovery. A window that lives in the clip table belongs in
|
|
30
|
+
* `AnimationClip.from(clip, { from, to })` instead. Not combined with `phase`. Hosts without the
|
|
31
|
+
* window play the whole clip. */
|
|
32
|
+
start?: number;
|
|
33
|
+
end?: number;
|
|
25
34
|
/** Enter the clip at a point in the GAIT CYCLE instead of at its start: `'match'` = the phase the
|
|
26
35
|
* layer shows right now (the walk's left foot is down → the turn clip starts where its left foot
|
|
27
36
|
* is down too, so nothing slides), or a number 0–1. Clips without a gait cycle ignore it. */
|
|
@@ -302,6 +311,9 @@ export declare class Core {
|
|
|
302
311
|
private clipNames;
|
|
303
312
|
/** Create the native animator on demand. False = nothing to animate (warned). */
|
|
304
313
|
ensure(): boolean;
|
|
314
|
+
/** The native animator for the RIG alone — an IK chain or a socket on a model that has no clips
|
|
315
|
+
* still needs the joint tree described to the engine. False = no transform hierarchy (warned). */
|
|
316
|
+
ensureRig(): boolean;
|
|
305
317
|
destroy(): void;
|
|
306
318
|
newLayer(options?: LayerOptions): LayerRec;
|
|
307
319
|
addLayer(options: LayerOptions): Layer;
|
|
@@ -392,12 +404,31 @@ export declare class Core {
|
|
|
392
404
|
/** Stride / orientation warping, as the engine's fixed-order parameter array. */
|
|
393
405
|
private _warp?;
|
|
394
406
|
setWarp(params: Float32Array): void;
|
|
407
|
+
/** The body's world velocity this frame (m/s) — the game side of the stride / orientation fit. Nothing
|
|
408
|
+
* to feed before the animator exists; hosts without the warp stage have no method. */
|
|
409
|
+
setMotion(vx: number, vy: number, vz: number): void;
|
|
395
410
|
/** The feet stage (lock / ground IK), as the engine's fixed-order parameter array. */
|
|
396
411
|
private _feetParams?;
|
|
397
412
|
setFeetParams(params: Float32Array): void;
|
|
398
413
|
/** One foot's lock state after this frame's evaluation into `out` (8 floats); false = no such foot
|
|
399
414
|
* or no feet stage on this host. */
|
|
400
415
|
footState(side: 0 | 1, out: Float32Array): boolean;
|
|
416
|
+
private static _warnedIk;
|
|
417
|
+
private hasIk;
|
|
418
|
+
/** A chain ending in `endEntity` (kind 0 two-bone: the bone, its parent, its grandparent; 1 look-at). 0 = none. */
|
|
419
|
+
ikCreate(kind: 0 | 1, endEntity: number): number;
|
|
420
|
+
ikDestroy(ik: number): void;
|
|
421
|
+
ikSet(ik: number, params: Float32Array): void;
|
|
422
|
+
ikNodes(ik: number, target: number, pole: number, rotation: number): void;
|
|
423
|
+
ikAnchor(ik: number, socket: string): void;
|
|
424
|
+
ikState(ik: number, out: Float32Array): boolean;
|
|
425
|
+
/** Sockets by "set/name", replayed when the animator is (re)created. */
|
|
426
|
+
private readonly _sockets;
|
|
427
|
+
/** Define a socket on joint `joint` (a bone's entity): a NODE socket (read by the engine every frame) or a
|
|
428
|
+
* fixed TRS in the joint's space. set "" = the live set, any other name = a donor's. */
|
|
429
|
+
setSocket(set: string, name: string, joint: number, node: number, trs: Float32Array | null): void;
|
|
430
|
+
removeSocket(set: string, name: string): void;
|
|
431
|
+
private pushSocket;
|
|
401
432
|
private readonly _steps;
|
|
402
433
|
onStepHandler(cb: StepHandler): void;
|
|
403
434
|
offStepHandler(cb: StepHandler): void;
|
|
@@ -33,6 +33,31 @@ export interface RagdollPart {
|
|
|
33
33
|
/** A one-way joint instead of the cone. */
|
|
34
34
|
hinge?: RagdollHinge;
|
|
35
35
|
}
|
|
36
|
+
/** How the body lies: on its back (the chest points up), prone (the chest points down), or on a side. */
|
|
37
|
+
export type RagdollFacing = "up" | "down" | "side";
|
|
38
|
+
export interface RagdollActivateOptions {
|
|
39
|
+
/** A LAUNCH added to every part's own motion (world m/s) — an explosion, a throw. The bones' own
|
|
40
|
+
* motion (the run, the swinging arms) is measured by the engine and needs no help. */
|
|
41
|
+
velocity?: Vec3Like;
|
|
42
|
+
/** The motors' strength from the first step (default: the current `strength`). */
|
|
43
|
+
strength?: number;
|
|
44
|
+
/** The root anchored to the animation from the first step (default: the current `anchored`). */
|
|
45
|
+
anchored?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface RagdollDeactivateOptions {
|
|
48
|
+
/** Seconds the animator takes to transition OUT of the fallen pose into whatever plays next (a
|
|
49
|
+
* get-up take started right after, or the loop). 0 (default) = a cut. Move the model node under
|
|
50
|
+
* the hips before this call: the bones are handed back against its new transform. */
|
|
51
|
+
blend?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface RagdollHitOptions {
|
|
54
|
+
/** How long the body stays powered before the bones go back to the animator (s, default 0.6). */
|
|
55
|
+
duration?: number;
|
|
56
|
+
/** The transition out of the reaction's last physical pose (s, default 0.25). */
|
|
57
|
+
blend?: number;
|
|
58
|
+
/** The motors' strength during the reaction (default 1). */
|
|
59
|
+
strength?: number;
|
|
60
|
+
}
|
|
36
61
|
export declare class Ragdoll extends Aspect<"ragdoll", Node> {
|
|
37
62
|
static readonly aspect = "ragdoll";
|
|
38
63
|
/** The parts: `'humanoid'` (default) finds the standard bones by name; a list places bodies on any
|
|
@@ -51,36 +76,86 @@ export declare class Ragdoll extends Aspect<"ragdoll", Node> {
|
|
|
51
76
|
* never shoves or blocks anything and costs nothing when they meet. `'all'`: a regular dynamic
|
|
52
77
|
* body that bumps into everything (and gets kicked awake by everything). */
|
|
53
78
|
collide: "static" | "all";
|
|
54
|
-
/** Once every part has come to rest the parts turn static where they lie (default
|
|
55
|
-
* holds, nothing can wake a settled body and it costs the solver nothing —
|
|
56
|
-
* `activate()` still work (activate makes it dynamic again).
|
|
79
|
+
/** Once every part of a LIMP body has come to rest the parts turn static where they lie (default
|
|
80
|
+
* true): the pose holds, nothing can wake a settled body and it costs the solver nothing —
|
|
81
|
+
* `deactivate()` / `activate()` still work (activate makes it dynamic again). A driven or anchored
|
|
82
|
+
* body never freezes. */
|
|
57
83
|
freeze: boolean;
|
|
58
|
-
/** Seconds after
|
|
59
|
-
*
|
|
84
|
+
/** Seconds limp after which the body freezes whatever it is doing — a twitch on a slope or a pile
|
|
85
|
+
* never sleeps on its own. 0 (default) = no cap. */
|
|
60
86
|
freezeAfter: number;
|
|
87
|
+
/** The joint motors: the position spring's frequency in Hz (default 6 — higher = a stiffer, quicker
|
|
88
|
+
* return to the animated pose) and damping ratio (default 1 = critical, no overshoot). */
|
|
89
|
+
driveFrequency: number;
|
|
90
|
+
driveDamping: number;
|
|
91
|
+
/** The motors' torque limit at strength 1, in N·m per kg of the part (default 12: ~180 N·m at the
|
|
92
|
+
* hips of an 80 kg body, ~25 at a forearm). Lower = a hit displaces a limb more before the
|
|
93
|
+
* animation wins it back. */
|
|
94
|
+
driveTorque: number;
|
|
95
|
+
/** Joint friction in N·m per kg of the part (default 0.3): a torque that resists any joint motion,
|
|
96
|
+
* motor or not — a limp body folds instead of flopping like jelly. */
|
|
97
|
+
jointFriction: number;
|
|
98
|
+
/** Where the joint limits come from. `'clips'` (default): measured from the animation — at the first
|
|
99
|
+
* activation that finds clips on the model's animator, every joint's swing and twist range over
|
|
100
|
+
* every bound clip becomes its limit (plus `limitsMargin` on each side), so the motors never
|
|
101
|
+
* target a pose the limits forbid and a limp body settles into poses the clips use; until clips
|
|
102
|
+
* are bound the part table's cones apply. `'table'`: the part table's cones and hinges only. */
|
|
103
|
+
limits: "clips" | "table";
|
|
104
|
+
/** Degrees added on each side of a learned range (default 10). */
|
|
105
|
+
limitsMargin: number;
|
|
61
106
|
static fields: FieldMeta<Ragdoll>;
|
|
62
107
|
private _id;
|
|
63
108
|
private _active;
|
|
64
109
|
private _bones;
|
|
110
|
+
private _strength;
|
|
111
|
+
private _anchored;
|
|
112
|
+
private _hipsFwd;
|
|
113
|
+
private _hipsUp;
|
|
114
|
+
private _ramp;
|
|
115
|
+
private _release;
|
|
65
116
|
onAttach(): void;
|
|
66
117
|
onDetach(): void;
|
|
67
|
-
/** Hand the bones to physics from the pose they are in right now
|
|
68
|
-
*
|
|
69
|
-
activate(opts?:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
deactivate(): void;
|
|
118
|
+
/** Hand the bones to physics from the pose they are in right now, each moving as it did over the
|
|
119
|
+
* last two frames (the engine measures: a runner keeps travelling, a swinging arm keeps swinging). */
|
|
120
|
+
activate(opts?: RagdollActivateOptions): boolean;
|
|
121
|
+
/** Take the bones back: the animator's pose shows again from the next frame — through a `blend`
|
|
122
|
+
* out of the fallen pose when asked (play the get-up take right after, with its own fade: it
|
|
123
|
+
* starts from where the body lies). */
|
|
124
|
+
deactivate(opts?: RagdollDeactivateOptions): void;
|
|
74
125
|
/** Physics owns the bones right now. */
|
|
75
126
|
get active(): boolean;
|
|
76
127
|
/** Active and every part asleep (or frozen) — the body has come to rest. */
|
|
77
128
|
get settled(): boolean;
|
|
129
|
+
/** The joint motors' strength, 0..1: how hard every joint is pulled toward the pose the animator
|
|
130
|
+
* shows (0 = off — a limp body). Kept across activations. */
|
|
131
|
+
get strength(): number;
|
|
132
|
+
set strength(v: number);
|
|
133
|
+
/** The hips follow the animation kinematically (the body stands in its clip while physics moves the
|
|
134
|
+
* limbs — hit reactions, a stagger). Off = the hips are a free body (a fall). */
|
|
135
|
+
get anchored(): boolean;
|
|
136
|
+
set anchored(v: boolean);
|
|
137
|
+
/** The joints give way: the strength ramps to 0 over `seconds` and the anchor comes off — a body
|
|
138
|
+
* shot mid-stride keeps its pose for a moment and then collapses, instead of switching off. */
|
|
139
|
+
goLimp(seconds?: number): void;
|
|
140
|
+
/** A flinch: the body powers up anchored to its animation (if it is not already active), the struck
|
|
141
|
+
* part gets the impulse (N·s, at a world point), and after `duration` the bones go back to the
|
|
142
|
+
* animator through `blend`. On a limp body (a corpse) it is just the impulse. */
|
|
143
|
+
hit(bone: string, v: Vec3Like, at?: Vec3Like, opts?: RagdollHitOptions): boolean;
|
|
78
144
|
/** The root part's bone (the hips): where the body is. */
|
|
79
145
|
get root(): Node | null;
|
|
146
|
+
/** How the body lies: `'up'` on its back (the chest points up), `'down'` prone, `'side'` otherwise.
|
|
147
|
+
* Read while it is down, to pick the get-up take. */
|
|
148
|
+
get facing(): RagdollFacing;
|
|
149
|
+
/** Where the head points along the ground, as a yaw in degrees (the model node's `eulerAngles` y
|
|
150
|
+
* that faces that way): where a get-up take that rises head-first ends up facing. A body still
|
|
151
|
+
* upright answers with the way its chest faces. */
|
|
152
|
+
get heading(): number;
|
|
80
153
|
/** The bones that carry a part, in order. */
|
|
81
154
|
get bones(): string[];
|
|
82
155
|
/** The rigid-body id of a part (0 if none) — for the plain body calls. */
|
|
83
156
|
bodyOf(bone: string): number;
|
|
84
157
|
/** Push one part: an impulse in N·s, at a world point (a hit) or through its centre. Wakes the body. */
|
|
85
158
|
impulse(bone: string, v: Vec3Like, at?: Vec3Like): boolean;
|
|
159
|
+
/** The strength ramp (goLimp) and the hit reaction's hand-back. */
|
|
160
|
+
update(dt: number): void;
|
|
86
161
|
}
|
|
@@ -5,11 +5,13 @@ import { Geometry } from "../Geometry";
|
|
|
5
5
|
import { type ColorInput } from "../../core/color";
|
|
6
6
|
import { Vec3, type Vec3Like } from "../../math/vec";
|
|
7
7
|
export type TerrainLayer = {
|
|
8
|
-
/** Albedo texture (a URL / `asset()` handle, or a loaded Texture). Unset = white.
|
|
8
|
+
/** Albedo texture (a URL / `asset()` handle, or a loaded Texture). Unset = white. Its ALPHA is the layer's roughness
|
|
9
|
+
* map (`lecodes assets terrain-pack --roughness` puts it there): an opaque albedo reads 1. */
|
|
9
10
|
albedo?: string | Texture;
|
|
10
11
|
/** Metres per texture repeat. Default 8. */
|
|
11
12
|
tiling?: number;
|
|
12
|
-
/** Perceptual roughness of the layer
|
|
13
|
+
/** Perceptual roughness of the layer — a factor on the albedo's alpha (its roughness map), the whole value when the
|
|
14
|
+
* albedo is opaque. A terrain has no metallic: ground is a dielectric. Default 1. */
|
|
13
15
|
roughness?: number;
|
|
14
16
|
/** Normal-map strength (0 = the layer's slot of the pack is not read). Default 0 — set 1 when the
|
|
15
17
|
* layer has a normal map in `normals`. */
|
|
@@ -174,6 +176,14 @@ export declare class Terrain {
|
|
|
174
176
|
heightAt(x: number, z: number): number;
|
|
175
177
|
/** The drawn triangle's normal at a local (x, z) (unit Vec3, +Y up). */
|
|
176
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;
|
|
177
187
|
/** The smooth (vertex) normal at integer sample (ix, iz). */
|
|
178
188
|
sampleNormal(ix: number, iz: number): Vec3;
|
|
179
189
|
/** Extent in local metres: `[width, depth]`. */
|
package/dist/types/inject.d.ts
CHANGED
|
@@ -58,8 +58,12 @@ export { Presentable } from "./ui/UI";
|
|
|
58
58
|
export type { PresentOptions, Transition, TransitionName, TransitionSpec, TransitionTransform } from "./ui/UI";
|
|
59
59
|
export type { UINode, UINodeChild } from "./ui/UINode";
|
|
60
60
|
export { theme, type ThemeValues, type ThemeAccessors } from "./ui/theme";
|
|
61
|
-
export { animate,
|
|
61
|
+
export { animate, type AnimateOptions, type AnimateValue, type AnimateOut } from "./animate/tween/animateValue";
|
|
62
62
|
export { cubicBezier } from "./animate/bezier";
|
|
63
|
+
export { Timeline, type TimelineOptions, type TimelineAddOptions, type TimelinePosition } from "./animate/tween/Timeline";
|
|
64
|
+
export { type Animation } from "./animate/tween/Animation";
|
|
65
|
+
export { type TweenMeta } from "./animate/tween/spec";
|
|
66
|
+
export { type EasingInput } from "./animate/tween/easing";
|
|
63
67
|
export { easeIn, easeOut, easeInOut } from "./animate/easings";
|
|
64
68
|
export { QRScanner } from "./plugins/qr";
|
|
65
69
|
export { CameraView, type CameraFacing } from "./plugins/camera";
|
|
@@ -96,7 +100,7 @@ export { Vehicle } from "./gl/vehicle/Vehicle";
|
|
|
96
100
|
export type { DriveLayout, DifferentialMode, EngineConfig, SteeringConfig, SteeringFeedback, SteeringDriver, AeroConfig } from "./gl/vehicle/Vehicle";
|
|
97
101
|
export { Wheel, Tire, resolveTire } from "./gl/vehicle/Wheel";
|
|
98
102
|
export { Ragdoll } from "./gl/physics/Ragdoll";
|
|
99
|
-
export type { RagdollPart, RagdollHinge } from "./gl/physics/Ragdoll";
|
|
103
|
+
export type { RagdollPart, RagdollHinge, RagdollFacing, RagdollActivateOptions, RagdollDeactivateOptions, RagdollHitOptions } from "./gl/physics/Ragdoll";
|
|
100
104
|
export type { Point, WheelSuspension } from "./gl/vehicle/Wheel";
|
|
101
105
|
export { AnimationClip } from "./gl/animation/AnimationClip";
|
|
102
106
|
export type { ClipDef, ClipTrackDef, ClipKey } from "./gl/animation/AnimationClip";
|
|
@@ -117,6 +121,8 @@ export type { DynamicBoneCurve, DynamicBoneFloor, DynamicBoneColliders } from ".
|
|
|
117
121
|
export type { IKTwoBone, IKLookAt } from "./gl/animation/IK";
|
|
118
122
|
export { Light } from "./gl/Light";
|
|
119
123
|
export { Lightmap } from "./gl/Lightmap";
|
|
124
|
+
export { Foliage } from "./gl/Foliage";
|
|
125
|
+
export type { FoliageOptions, FoliageWind } from "./gl/Foliage";
|
|
120
126
|
export { Terrain } from "./gl/terrain/Terrain";
|
|
121
127
|
export type { TerrainOptions, TerrainLayer, TerrainRegion, ConformOptions, RibbonOptions, AutoPaintRules, SculptOptions, TerrainHit, TerrainSnapshot } from "./gl/terrain/Terrain";
|
|
122
128
|
export { NavMesh, NavCrowd } from "./gl/nav/NavMesh";
|
|
@@ -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
|
/**
|
|
@@ -5,6 +5,8 @@ import { Scene, type SceneOptions } from "../gl/Scene";
|
|
|
5
5
|
import { Node } from "../gl/Node";
|
|
6
6
|
import { Mesh } from "../gl/Mesh";
|
|
7
7
|
import { Model } from "../gl/Model";
|
|
8
|
+
import { type LightmapTransmit } from "../gl/Lightmap";
|
|
9
|
+
import { type FoliageOptions } from "../gl/Foliage";
|
|
8
10
|
import { type TerrainLayer, type TerrainRegion, type TerrainOptions } from "../gl/terrain/Terrain";
|
|
9
11
|
import { Light, type SunOptions } from "../gl/Light";
|
|
10
12
|
import { type MaterialDef } from "./material";
|
|
@@ -130,6 +132,12 @@ export type SceneNodeDef = {
|
|
|
130
132
|
* Default: static unless a `Physics` aspect moves the node (`dynamic` — Physics' default — or
|
|
131
133
|
* `kinematic`). Set it only to override that rule; prefab subtrees inherit the verdict. */
|
|
132
134
|
lightmap?: boolean;
|
|
135
|
+
/** `model` nodes: vegetation — load through the FOLIAGE tier (wind, touch bending, per-copy tint; see
|
|
136
|
+
* `Foliage`). `{ fade: [start, end] }` also thins the cards out over that distance range (m) and drops the
|
|
137
|
+
* copy past `end` — for ground cover. The fade is per ASSET: every node of the same GLB shares it. */
|
|
138
|
+
foliage?: boolean | {
|
|
139
|
+
fade?: [number, number];
|
|
140
|
+
};
|
|
133
141
|
/** Navigation (a scene with `env.navmesh`, see navmesh.md): every STATIC body is walkable by
|
|
134
142
|
* default. `false` leaves this one out of the bake; `'unwalkable'` cuts its footprint out
|
|
135
143
|
* (nobody stands on or crosses it). */
|
|
@@ -144,41 +152,44 @@ export type SceneCameraDef = CameraProjectionDef & {
|
|
|
144
152
|
/** Point the camera looks at. */
|
|
145
153
|
target?: Vec3Like;
|
|
146
154
|
};
|
|
147
|
-
/** `env.lightmap` — the level's baked lighting (
|
|
148
|
-
*
|
|
155
|
+
/** `env.lightmap` — the level's baked lighting (packages/creator-bake): the files `lecodes lightmap bake`
|
|
156
|
+
* writes. Absent = real-time only. */
|
|
149
157
|
export type SceneLightmapDef = {
|
|
150
|
-
/** `asset('./assets/lightmap/
|
|
158
|
+
/** `asset('./assets/lightmap/level.bake')` */
|
|
151
159
|
data: string;
|
|
152
|
-
/** `asset('./assets/lightmap/
|
|
153
|
-
* (`lecodes lightmap bake --pages`), every page in order: `[asset('x.ktx2'), asset('
|
|
154
|
-
|
|
155
|
-
/** `asset('./assets/lightmap/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
/** `asset('./assets/lightmap/level-light.ktx2')` — or, for a bake that took more than one atlas PAGE
|
|
161
|
+
* (`lecodes lightmap bake --pages`), every page in order: `[asset('x-light.ktx2'), asset('x-light_1.ktx2')]`. */
|
|
162
|
+
light: string | string[];
|
|
163
|
+
/** `asset('./assets/lightmap/level-aux.ktx2')` (pages like `light`) — sun / sky visibility + light direction. */
|
|
164
|
+
aux: string | string[];
|
|
165
|
+
/** DEBUG: the page sets a `lecodes lightmap bake --split` wrote (`<stem>-direct[_n].ktx2`, `<stem>-indirect[_n].ktx2`),
|
|
166
|
+
* pages like `light` — the `Lightmap.debug("direct" | "indirect")` views bind them in place of `light`. */
|
|
167
|
+
direct?: string | string[];
|
|
168
|
+
indirect?: string | string[];
|
|
169
|
+
/** `asset('./assets/lightmap/level-probes.ktx2')` — the bake's reflection probes (one prefiltered cubemap of the level's
|
|
170
|
+
* radiance per probe; every static reflects the nearest). Absent = statics reflect the sky's SH alone. */
|
|
171
|
+
probes?: string;
|
|
172
|
+
/** FOR THE BAKE: the radiance in cd / m² of emission 1.0 on this level (emissive factor x strength x map) - every lit
|
|
173
|
+
* region of an emissive surface bakes as a rectangle lamp. An imported pack's emission is a LOOK (the school's panels
|
|
174
|
+
* say 10); this is where the level says what they give: a 1.3 m ceiling panel of ~8000 lm is ~1600 nits. Default: what
|
|
175
|
+
* the camera makes of 1.0 (`1.2 x 2^EV100`). 0 = emissive surfaces light nothing. `--emissive-nits` overrides. */
|
|
176
|
+
emissiveNits?: number;
|
|
177
|
+
/** `false` = the emissive surfaces light nothing in the bake - the level is lit by its lamps (`Light.point` with a
|
|
178
|
+
* `bakeArea` next to every panel, the Unity packs' way) and the panels are decoration; `emissiveNits` then only says how
|
|
179
|
+
* bright their glow is DRAWN (scene-referred: nits through the camera's exposure). Default true. */
|
|
180
|
+
emissiveBake?: boolean;
|
|
181
|
+
/** FOR THE BAKE: materials that let light THROUGH them, by glTF material name (`"name*"` = every name with that start) →
|
|
182
|
+
* the share of a shadow ray that passes, tinted by the material's base colour x map: `{ mat_awning: 0.3 }` puts the
|
|
183
|
+
* awning's warm, patterned light on the sand. The surface stays opaque - baked, drawn as before, a shadow caster.
|
|
184
|
+
* `{ through, diffuse }` splits it: `through` goes straight (the picture of the map), `diffuse` is scattered by the
|
|
185
|
+
* fibres (the underside glows, a soft fill with no picture) - dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */
|
|
186
|
+
transmit?: Record<string, LightmapTransmit>;
|
|
187
|
+
/** `asset('./assets/lightmap/level.lgrid')` — THE LIGHT GRID for movers: every node a Physics aspect or a
|
|
188
|
+
* CharacterController moves (and what code marks with `Lightmap.track`) takes its ambient light from the bake at the
|
|
189
|
+
* place it is at, whatever its shader. Absent = movers keep the scene's IBL. */
|
|
162
190
|
volume?: string;
|
|
163
|
-
/**
|
|
164
|
-
|
|
165
|
-
/** Multiplier on the ambient share in the shadow math (1 = filament's own darkness). Default 1. */
|
|
166
|
-
ambientScale?: number;
|
|
167
|
-
/** How much of the baked ambient occlusion applies: 1 = all of it, 0 = none. An interior lit by its
|
|
168
|
-
* ambient probe alone can want less than the geometric truth. Default 1. */
|
|
169
|
-
aoStrength?: number;
|
|
170
|
-
/** Multiplier on the baked point lights' irradiance (default 1) - dial the lamps up or down
|
|
171
|
-
* without a re-bake, since their irradiance lives in the atlas. Scales the light volume with the
|
|
172
|
-
* atlas, so movers match the statics. See `LightmapLoadOptions.lightBoost`. */
|
|
173
|
-
lightBoost?: number;
|
|
174
|
-
/** Multiplier on the light VOLUME's irradiance alone (default = `lightBoost`). Since the volume is an
|
|
175
|
-
* ambient cube (2026-08-31) movers shade like the statics and the default is right; it stays as a
|
|
176
|
-
* trim. See `LightmapLoadOptions.volumeBoost`. */
|
|
177
|
-
volumeBoost?: number;
|
|
178
|
-
/** Occluder-only statics (props without lightmap UVs): `"baked"` (default) = their shadow is in the
|
|
179
|
-
* atlas, they stop casting in real time and the shadow pass draws only the movers; `"realtime"` =
|
|
180
|
-
* they keep casting (their shadow on other non-receiver props). See `LightmapLoadOptions.occluderShadows`. */
|
|
181
|
-
occluderShadows?: "baked" | "realtime";
|
|
191
|
+
/** A DEBUG multiplier on the atlas' lux (default 1). */
|
|
192
|
+
lightScale?: number;
|
|
182
193
|
};
|
|
183
194
|
/** `env.navmesh` — the level's navigation mesh (see navmesh.md): the file `lecodes navmesh bake`
|
|
184
195
|
* writes, the agent size it is built for, and the named areas. Absent = no navigation. */
|
|
@@ -199,6 +210,7 @@ export type SceneDef = {
|
|
|
199
210
|
env?: SceneOptions & {
|
|
200
211
|
lightmap?: SceneLightmapDef;
|
|
201
212
|
navmesh?: SceneNavmeshDef;
|
|
213
|
+
foliage?: FoliageOptions;
|
|
202
214
|
};
|
|
203
215
|
camera?: SceneCameraDef;
|
|
204
216
|
nodes?: Record<string, SceneNodeDef>;
|