lecodes-sdk 2.4.1 → 2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/types/core/Aspect.d.ts +34 -5
  2. package/dist/types/g2/OneWay2D.d.ts +0 -1
  3. package/dist/types/g2/Physics2D.d.ts +8 -6
  4. package/dist/types/g2/Scene2D.d.ts +1 -1
  5. package/dist/types/g2/Shape2D.d.ts +43 -15
  6. package/dist/types/gl/Model.d.ts +3 -2
  7. package/dist/types/gl/Scene.d.ts +1 -1
  8. package/dist/types/gl/animation/DynamicBone.d.ts +99 -35
  9. package/dist/types/gl/animation/IK.d.ts +0 -1
  10. package/dist/types/gl/nav/NavAgent.d.ts +3 -2
  11. package/dist/types/gl/physics/Physics.d.ts +4 -5
  12. package/dist/types/gl/physics/Shape.d.ts +40 -15
  13. package/dist/types/gl/vehicle/Vehicle.d.ts +54 -35
  14. package/dist/types/gl/vehicle/Wheel.d.ts +31 -10
  15. package/dist/types/plugins/gen/ar/contract.d.ts +152 -0
  16. package/dist/types/plugins/gen/ar/sdk/ar.d.ts +47 -21
  17. package/dist/types/plugins/gen/ar/sdk/ar.gen.d.ts +17 -3
  18. package/dist/types/plugins/gen/audio-recorder/contract.d.ts +64 -0
  19. package/dist/types/plugins/gen/browser/contract.d.ts +108 -0
  20. package/dist/types/plugins/gen/browser/sdk/browser.d.ts +2 -1
  21. package/dist/types/plugins/gen/camera/contract.d.ts +27 -0
  22. package/dist/types/plugins/gen/geolocation/contract.d.ts +52 -0
  23. package/dist/types/plugins/gen/map/contract.d.ts +144 -0
  24. package/dist/types/plugins/gen/push/contract.d.ts +83 -0
  25. package/dist/types/plugins/gen/qr-scanner/contract.d.ts +16 -0
  26. package/dist/types/plugins/gen/speech/contract.d.ts +67 -0
  27. package/dist/types/plugins/gen/webrtc/contract.d.ts +342 -0
  28. package/dist/types/version.d.ts +1 -1
  29. package/dist/types.json +1 -1
  30. package/package.json +1 -1
  31. package/src/animate/tween/Timeline.ts +175 -175
  32. package/src/bridges/gl.d.ts +5 -3
  33. package/src/compile/compileProject.ts +45 -10
  34. package/src/compile/index.ts +7 -0
  35. package/src/compile/webHalf.ts +255 -0
  36. package/src/core/Aspect.ts +118 -35
  37. package/src/g2/OneWay2D.ts +0 -2
  38. package/src/g2/Physics2D.ts +8 -16
  39. package/src/g2/Scene2D.ts +1 -1
  40. package/src/g2/Shape2D.ts +51 -22
  41. package/src/gl/CameraPlace.ts +52 -52
  42. package/src/gl/Light.ts +257 -257
  43. package/src/gl/Mesh.ts +120 -120
  44. package/src/gl/Model.ts +3 -2
  45. package/src/gl/Scene.ts +1 -1
  46. package/src/gl/animation/DynamicBone.ts +549 -486
  47. package/src/gl/animation/IK.ts +0 -2
  48. package/src/gl/nav/NavAgent.ts +14 -12
  49. package/src/gl/physics/Physics.ts +4 -5
  50. package/src/gl/physics/Shape.ts +49 -23
  51. package/src/gl/scenarios.ts +291 -291
  52. package/src/gl/vehicle/Vehicle.ts +102 -58
  53. package/src/gl/vehicle/Wheel.ts +45 -11
  54. package/src/plugins/gen/ar/contract.d.ts +35 -1
  55. package/src/plugins/gen/ar/sdk/ar.gen.ts +25 -6
  56. package/src/plugins/gen/ar/sdk/ar.ts +102 -35
  57. package/src/plugins/gen/browser/sdk/browser.ts +11 -1
  58. package/src/version.ts +1 -1
@@ -25,8 +25,10 @@ export type With<N, A extends Aspect<any, any, any>> = N & UnionToIntersection<A
25
25
  * attach time, keyed by the aspect class's runtime `aspect` name.
26
26
  */
27
27
  export declare abstract class AspectHost<E extends EventMap = EventMap> extends Emitter<E> {
28
- /** Attach (and configure) an aspect, or reconfigure it if already present. Returns the node typed
29
- * as now-having that aspect (so no guard/`?.` is needed afterwards). Rejects a wrong target node. */
28
+ /** Attach an aspect built from `opts` (a class already on the node is detached first and REBUILT
29
+ * from exactly these options — a structural change; a live value is a property write on
30
+ * `node.<accessor>`). Returns the node typed as now-having that aspect (so no guard/`?.` is
31
+ * needed afterwards). Rejects a wrong target node. */
30
32
  aspect<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;
31
33
  /** Safe access — undefined if the aspect isn't attached. */
32
34
  get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;
@@ -107,9 +109,36 @@ export declare abstract class Aspect<K extends string, P = Node, E extends Event
107
109
  protected onAttach?(): void;
108
110
  /** Release what onAttach acquired. */
109
111
  protected onDetach?(): void;
110
- /** Called after `node.aspect(Ctor, opts)` re-assigns options on an ALREADY attached aspect (a
111
- * pre-attached one like `model.anim`): rebuild whatever was derived from the options at attach. */
112
- protected onReconfigure?(): void;
112
+ /**
113
+ * LIVE PROPERTIES. A value the engine must hear about is a get/set pair whose setter stores it and
114
+ * calls `this.dirty()`; `flush()` then runs ONCE before the next physics step — at the start of
115
+ * the early phase for a write made since the last frame, right after the early updaters for one
116
+ * made in an `updateBefore` — however many properties changed, one send. `node.aspect(Ctor, opts)`
117
+ * and the scene file write the same setters. Before attach a setter only stores (onAttach sends
118
+ * everything); after detach nothing flushes. A value with a bridge call of its own, or one whose
119
+ * result the caller reads back at once (a Shape's dimensions: `controller.resizing`), skips the
120
+ * batch and pushes from its setter.
121
+ *
122
+ * get radius(): number { return this._radius }
123
+ * set radius(v: number) { this._radius = v; this.dirty() }
124
+ * protected flush(): void { _creator.thingSetTuning(this._id, this._settings()) }
125
+ */
126
+ protected dirty(): void;
127
+ /** Send what the setters changed — see `dirty()`. */
128
+ protected flush?(): void;
129
+ /**
130
+ * A nested config object as a LIVE VIEW: every key of `defaults` becomes an accessor whose setter
131
+ * stores and calls `this.dirty()`, so `wheel.suspension.stiffness = 2` reaches the engine like any
132
+ * live property. `value` is taken WHOLE: a key it leaves out is the default, nothing of a previous
133
+ * object survives (`wheel.suspension = { stiffness: 2 }` is stiffness 2 and the default travel and
134
+ * damping). Writing `undefined` to a key restores its default. One level deep: a value that is
135
+ * itself an object is replaced, not watched.
136
+ *
137
+ * private _suspension = this.live(SUSPENSION_DEFAULTS)
138
+ * get suspension(): WheelSuspension { return this._suspension }
139
+ * set suspension(v: WheelSuspension) { this._suspension = this.live(SUSPENSION_DEFAULTS, v); this.dirty() }
140
+ */
141
+ protected live<T extends object>(defaults: T, value?: Partial<T>): T;
113
142
  /**
114
143
  * GENERATOR aspects: (re)build the derived output under `this.generated` — must be idempotent
115
144
  * (clear, then create). Call it from `onAttach()` for play mode; a class opting in with
@@ -19,6 +19,5 @@ export declare class OneWay2D extends Aspect<"oneWay", Node2D> {
19
19
  set enabled(v: boolean);
20
20
  onAttach(): void;
21
21
  onDetach(): void;
22
- onReconfigure(): void;
23
22
  private _push;
24
23
  }
@@ -28,10 +28,14 @@ export declare class Physics2D extends Aspect<"physics", Node2D> {
28
28
  * Default "dynamic", and LIVE: freeze a crate into `'static'`, hand a ragdoll to `'dynamic'`. */
29
29
  get motion(): MotionType;
30
30
  set motion(m: MotionType);
31
- /** Lock rotation (essential for platformer characters). */
32
- fixedRotation: boolean;
33
- /** Continuous collision for fast-moving bodies (projectiles). */
34
- bullet: boolean;
31
+ private _fixedRotation;
32
+ /** Lock rotation (essential for platformer characters). Live. */
33
+ get fixedRotation(): boolean;
34
+ set fixedRotation(v: boolean);
35
+ private _bullet;
36
+ /** Continuous collision for fast-moving bodies (projectiles). Live. */
37
+ get bullet(): boolean;
38
+ set bullet(v: boolean);
35
39
  private _mass;
36
40
  private _friction;
37
41
  private _bounce;
@@ -63,8 +67,6 @@ export declare class Physics2D extends Aspect<"physics", Node2D> {
63
67
  get id(): number;
64
68
  onAttach(): void;
65
69
  onDetach(): void;
66
- /** Re-applying options (`node.aspect(Physics2D, {…})`) pushes the live ones through. */
67
- onReconfigure(): void;
68
70
  /** Linear velocity in world units/second (fresh Vec2 on read). */
69
71
  get velocity(): Vec2;
70
72
  set velocity(v: Vec2Like);
@@ -53,7 +53,7 @@ export declare class Scene2D implements Presentable {
53
53
  /** class → instance, the authoritative store (named accessors mirror this). Kept in the public
54
54
  * types: it is what makes a Scene2D a `SystemHost` there. */
55
55
  readonly _systems: Map<Function, Aspect<any, any, any>>;
56
- /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed
56
+ /** Build a system from `opts` (a class already on the scene is detached and built afresh). Returns the scene typed
57
57
  * as now-having it (`scene.system(Hud).hud`). A 3D `System<'x'>` (target Scene) is rejected here. */
58
58
  system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;
59
59
  /** Safe access — undefined if the system isn't attached. */
@@ -1,26 +1,48 @@
1
1
  import { Aspect } from "../core/Aspect";
2
+ import type { FieldMeta } from "../core/fields";
2
3
  import { type Vec2Like } from "../math/vec";
3
4
  import type { Node2D } from "./Node2D";
4
5
  export declare class Shape2D extends Aspect<"shape", Node2D> {
5
6
  static readonly aspect = "shape";
7
+ private _box?;
8
+ private _circle?;
9
+ private _cap?;
10
+ private _segment?;
11
+ private _polygon?;
12
+ private _chain?;
13
+ private _loop?;
14
+ private _flip?;
15
+ private _origin?;
6
16
  /** Box half-extents [hw, hh] (world units). */
7
- box?: Vec2Like;
17
+ get box(): Vec2Like | undefined;
18
+ set box(v: Vec2Like | undefined);
8
19
  /** Circle radius. */
9
- circle?: number;
20
+ get circle(): number | undefined;
21
+ set circle(v: number | undefined);
10
22
  /** Capsule between two local points, with a radius. */
11
- capsule?: {
23
+ get capsule(): {
12
24
  from: Vec2Like;
13
25
  to: Vec2Like;
14
26
  radius: number;
15
- };
27
+ } | undefined;
28
+ set capsule(v: {
29
+ from: Vec2Like;
30
+ to: Vec2Like;
31
+ radius: number;
32
+ } | undefined);
16
33
  /** Thin segment (an edge) between two local points. */
17
- segment?: {
34
+ get segment(): {
35
+ from: Vec2Like;
36
+ to: Vec2Like;
37
+ } | undefined;
38
+ set segment(v: {
18
39
  from: Vec2Like;
19
40
  to: Vec2Like;
20
- };
41
+ } | undefined);
21
42
  /** Convex polygon, up to 8 local points (a convex hull is computed — a CONCAVE outline silently
22
43
  * becomes its hull; use `chain` for those). */
23
- polygon?: Vec2Like[];
44
+ get polygon(): Vec2Like[] | undefined;
45
+ set polygon(v: Vec2Like[] | undefined);
24
46
  /**
25
47
  * A polyline of connected segments — the one shape that expresses a long CONCAVE surface (rolling
26
48
  * terrain, a cave wall) in one piece, seam-free. Pass only the points that should be solid; the
@@ -30,22 +52,28 @@ export declare class Shape2D extends Aspect<"shape", Node2D> {
30
52
  * must not self-intersect. It is ONE-SIDED: solid on the right of the point order — walk the points
31
53
  * so that the solid material is on your right, or set `flip`.
32
54
  */
33
- chain?: Vec2Like[];
55
+ get chain(): Vec2Like[] | undefined;
56
+ set chain(v: Vec2Like[] | undefined);
34
57
  /** `chain`: close the contour (an island / a room boundary). Needs at least 4 points. */
35
- loop?: boolean;
58
+ get loop(): boolean | undefined;
59
+ set loop(v: boolean | undefined);
36
60
  /** `chain`: put the solid side on the other side of the line. */
37
- flip?: boolean;
61
+ get flip(): boolean | undefined;
62
+ set flip(v: boolean | undefined);
38
63
  /** The collider's centre relative to the node, in world units. Applies to EVERY kind — it
39
64
  * translates a capsule's / segment's / polygon's / chain's points too, unlike the old `offset`. */
40
- origin?: Vec2Like;
65
+ get origin(): Vec2Like | undefined;
66
+ set origin(v: Vec2Like | undefined);
67
+ /** Scene-editor inspector: the geometry fields (accessors, so they are listed here by name). */
68
+ static fields: FieldMeta<Shape2D>;
41
69
  private _handle;
42
70
  onDetach(): void;
43
71
  /**
44
- * Re-configuring the aspect swaps the fixture in place — same body, same id, same velocity, same
45
- * position. Nothing happens when the geometry is unchanged, so re-applying the same options in a
46
- * loop is free.
72
+ * A dimension was written: swap the fixture in place — same body, same id, same velocity, same
73
+ * position. Nothing happens when the signature is unchanged, so writing the same dimensions every
74
+ * frame is free.
47
75
  */
48
- onReconfigure(): void;
76
+ private _changed;
49
77
  private _create;
50
78
  /**
51
79
  * Box2D's chain wants the two TANGENT points as extra entries and does not collide on its first or
@@ -34,8 +34,9 @@ export interface TrianglePick {
34
34
  }[];
35
35
  }
36
36
  export declare class Model extends Node {
37
- /** The model's Animator — always present, its clip table = the GLB's embedded clips. Configure
38
- * more (external clips, blend spaces, layers) with `model.aspect(Animator, {...})`. */
37
+ /** The model's Animator — always present, its clip table = the GLB's embedded clips. Add to it
38
+ * with `model.anim.addClip(name, clip)` (external clips), `model.anim.addLayer()`; set its fields
39
+ * (`model.anim.speed = 1.5`) — never `model.aspect(Animator, …)`, which would build a fresh one. */
39
40
  readonly anim: Animator;
40
41
  constructor(internalId: number | Handle);
41
42
  /** Does this model cast a real-time shadow? Unlike Mesh (one renderable) a GLB is a whole
@@ -194,7 +194,7 @@ export declare class Scene implements Presentable {
194
194
  /** class → instance, the authoritative store (named accessors mirror this). Kept in the public
195
195
  * types: it is what makes a Scene a `SystemHost` there. */
196
196
  readonly _systems: Map<Function, Aspect<any, any, any>>;
197
- /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed
197
+ /** Build a system from `opts` (a class already on the scene is detached and built afresh). Returns the scene typed
198
198
  * as now-having it (`scene.system(Hud).hud`). A `System<'x', Scene2D>` is rejected here. */
199
199
  system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;
200
200
  /** Safe access — undefined if the system isn't attached. */
@@ -27,23 +27,34 @@ export type DynamicBoneSide = "none" | "auto" | Vec3Like;
27
27
  * with `colliders: 'auto'` / `'humanoid'`, or listed explicitly. */
28
28
  export declare class DynamicBoneCollider extends Aspect<"dynamicBoneCollider", Node> {
29
29
  static readonly aspect = "dynamicBoneCollider";
30
+ private _radius;
30
31
  /** Radius in metres, in the world: the bone's scale does not touch it (`offset` / `end` are in the bone's own units). */
31
- radius: number;
32
+ get radius(): number;
33
+ set radius(v: number);
34
+ private _offset;
32
35
  /** Start of the capsule in the bone's local space (default: the bone's origin). */
33
- offset: Vec3Like;
36
+ get offset(): Vec3Like;
37
+ set offset(v: Vec3Like);
38
+ private _end?;
34
39
  /** End of the capsule in the bone's local space (a sphere when neither `end` nor `to` is set). */
35
- end?: Vec3Like;
40
+ get end(): Vec3Like | undefined;
41
+ set end(v: Vec3Like | undefined);
42
+ private _to?;
36
43
  /** The bone the capsule reaches (its origin), instead of `end`. */
37
- to?: string;
44
+ get to(): string | undefined;
45
+ set to(v: string | undefined);
46
+ private _oneSided;
38
47
  /** ONE-SIDED: the cloth belongs on the chain's `side` of this capsule (see DynamicBone.side). While the capsule
39
48
  * moves away from that side it puts a bone it has run into over to the side instead of carrying it — an arm
40
49
  * under a cape may push the cape back, never drag it forward round the body. Needs a `side` on the DynamicBone. */
41
- oneSided: boolean;
50
+ get oneSided(): boolean;
51
+ set oneSided(v: boolean);
42
52
  static fields: FieldMeta<DynamicBoneCollider>;
43
53
  private _id;
44
54
  private _segment;
45
55
  onAttach(): void;
46
- onReconfigure(): void;
56
+ /** A field changed: re-describe the capsule to the engine. Every field is live. */
57
+ protected flush(): void;
47
58
  onDetach(): void;
48
59
  }
49
60
  export declare class DynamicBone extends Aspect<"dynamicBone", Node> {
@@ -51,43 +62,68 @@ export declare class DynamicBone extends Aspect<"dynamicBone", Node> {
51
62
  /** Whether this host simulates dynamic bones. False, never a throw, on Web Lite and in headless
52
63
  * tests; there the aspect attaches, warns once, and `chain` stays empty. */
53
64
  static get supported(): boolean;
65
+ private _bones?;
54
66
  /** Only these bones (by name) join the chain — the root always does, a bone left out takes its
55
67
  * subtree with it. Default: the root's whole subtree. */
56
- bones?: string[];
68
+ get bones(): string[] | undefined;
69
+ set bones(v: string[] | undefined);
70
+ private _depth;
57
71
  /** Depth limit under the root (0 = no limit). */
58
- depth: number;
72
+ get depth(): number;
73
+ set depth(v: number);
74
+ private _radius;
59
75
  /** Particle radius for the collisions, metres. */
60
- radius: DynamicBoneCurve;
76
+ get radius(): DynamicBoneCurve;
77
+ set radius(v: DynamicBoneCurve);
78
+ private _stiffness;
61
79
  /** 0..1 — how fast a bone returns to the animated shape (per 1/60 s). 0 = a rope, 1 = rigid. */
62
- stiffness: DynamicBoneCurve;
80
+ get stiffness(): DynamicBoneCurve;
81
+ set stiffness(v: DynamicBoneCurve);
82
+ private _damping;
63
83
  /** 0..1 — velocity lost per 1/60 s. 0.02 swings like a rope, 0.1 settles like a tail, 0.3 is honey. */
64
- damping: DynamicBoneCurve;
84
+ get damping(): DynamicBoneCurve;
85
+ set damping(v: DynamicBoneCurve);
86
+ private _gravity;
65
87
  /** m/s² downward. A hanging rest pose feels none of it (the bone length cancels it); a pose that
66
88
  * sticks out droops by as much as `stiffness` lets it. */
67
- gravity: DynamicBoneCurve;
89
+ get gravity(): DynamicBoneCurve;
90
+ set gravity(v: DynamicBoneCurve);
91
+ private _angleLimit;
68
92
  /** Max deviation from the animated direction, degrees per bone (0 = free). */
69
- angleLimit: DynamicBoneCurve;
93
+ get angleLimit(): DynamicBoneCurve;
94
+ set angleLimit(v: DynamicBoneCurve);
95
+ private _mass;
70
96
  /** Relative mass per bone. A bone-length constraint moves its two ends in inverse proportion to
71
97
  * their masses (the root is kinematic): `[3, 1]` makes a tail's base carry its tip, `1` shares
72
98
  * evenly like a rope. */
73
- mass: DynamicBoneCurve;
99
+ get mass(): DynamicBoneCurve;
100
+ set mass(v: DynamicBoneCurve);
101
+ private _pinned?;
74
102
  /** Bones (by name) that ride the animation exactly while their subtrees still simulate: a sheet's
75
103
  * several roots under one anchor (a cloak's seven strips under the spine), so ONE chain owns them all
76
104
  * and `link` ties neighbouring strips — neighbours in THIS order, so list the strips round the ring
77
105
  * (front-left … back … front-right); the front stays open. */
78
- pinned?: string[];
106
+ get pinned(): string[] | undefined;
107
+ set pinned(v: string[] | undefined);
108
+ private _pinGive;
79
109
  /** Metres a PINNED bone may be pushed off its animated place by a collider — a soft pin. Its particle
80
110
  * collides and takes the edge pushes like a free bone (the strip below hangs from where it IS) and is
81
111
  * drawn back to the animation when the collider leaves; the bone's local translation follows. A hard
82
112
  * pin (0) at a capsule's edge made the first free bone below it jitter: the edge push on a segment
83
113
  * with an immovable end is a lever, and a touch near the root threw the child out. 2–3 cm for a
84
114
  * cloak's roots under a shoulder capsule. */
85
- pinGive: number;
115
+ get pinGive(): number;
116
+ set pinGive(v: number);
117
+ private _follow;
86
118
  /** 0..1 of the character's travel the chain takes rigidly (0 = the full whip on a dash, 1 = it
87
119
  * moves with the body and only the pose's own motion swings it). */
88
- follow: number;
120
+ get follow(): number;
121
+ set follow(v: number);
122
+ private _wind;
89
123
  /** World wind, m/s². */
90
- wind: Vec3Like;
124
+ get wind(): Vec3Like;
125
+ set wind(v: Vec3Like);
126
+ private _spin;
91
127
  /** The BODY'S TURN, ≥ 0. Above 0 the chain lives in the parent bone's ROTATING frame: `damping` acts
92
128
  * against the body's rigid motion (its travel plus its spin), so a heavily damped cloak RIDES a turn —
93
129
  * sweeps round with the back — instead of standing in the world while the character spins under it and
@@ -98,47 +134,74 @@ export declare class DynamicBone extends Aspect<"dynamicBone", Node> {
98
134
  * bigger fling. With low damping the frame reproduces a free particle (nothing is counted twice);
99
135
  * an animation's spine sway is ~1 % of a 900°/s turn. A rotation over 90° in one frame (a respawn
100
136
  * facing) counts as a snap, not a spin. 0 = the plain translational frame, no turn forces. */
101
- spin: number;
137
+ get spin(): number;
138
+ set spin(v: number);
139
+ private _spinInertia;
102
140
  /** With `spin`: the cloth's INERTIA against the body's turn, seconds — the cloth's own rotation follows the
103
141
  * body's with this time constant. It falls behind when a turn starts (by about ω·τ: 45° at 900°/s and 0.05),
104
142
  * rides once caught up, and keeps turning past the back when the body stops (the same angle, eased out over
105
143
  * τ). Smooth by construction. 0 = glued to the turn; large = the cloth stays in the world while the body spins. */
106
- spinInertia: number;
144
+ get spinInertia(): number;
145
+ set spinInertia(v: number);
146
+ private _link;
107
147
  /** 0..1 strength of the ties between neighbouring columns at the same depth (a cloak). */
108
- link: number;
148
+ get link(): number;
149
+ set link(v: number);
150
+ private _weight;
109
151
  /** 0..1 blend from the animation (0) to the simulation (1). At 0 nothing is simulated and the
110
152
  * chain re-arms on the animated pose when it comes back. */
111
- weight: number;
153
+ get weight(): number;
154
+ set weight(v: number);
155
+ private _rate;
112
156
  /** Substep rate, Hz (≤ 4 substeps per frame). */
113
- rate: number;
157
+ get rate(): number;
158
+ set rate(v: number);
159
+ private _teleport;
114
160
  /** A root jump longer than this in one frame (metres) resets the chain instead of whipping it. */
115
- teleport: number;
161
+ get teleport(): number;
162
+ set teleport(v: number);
163
+ private _floor;
116
164
  /** What the particles stay above: `'none'`, `'probe'`, a height, or a world point. */
117
- floor: DynamicBoneFloor;
165
+ get floor(): DynamicBoneFloor;
166
+ set floor(v: DynamicBoneFloor);
167
+ private _floorNormal;
118
168
  /** The floor plane's normal when `floor` is a point. */
119
- floorNormal: Vec3Like;
169
+ get floorNormal(): Vec3Like;
170
+ set floorNormal(v: Vec3Like);
171
+ private _floorFriction;
120
172
  /** Friction against the floor, a Coulomb coefficient: a resting bone's slide loses up to
121
173
  * `floorFriction · gravity · dt` of speed per substep (0 = ice, 1 = a rubber sole). While a bone
122
174
  * rests on the floor or a collider, `stiffness` and `angleLimit` let go of it: the surface's
123
175
  * reaction outranks the spring, or a hem folded on the floor would run away along it. */
124
- floorFriction: number;
176
+ get floorFriction(): number;
177
+ set floorFriction(v: number);
178
+ private _iterations;
125
179
  /** Constraint passes per substep (1..8, default 4). Each pass shares every bone length between its
126
180
  * ends, so a pull needs passes to travel down a long chain: a long rope may want 8, a short tail is
127
181
  * fine with 2. */
128
- iterations: number;
182
+ get iterations(): number;
183
+ set iterations(v: number);
184
+ private _colliders;
129
185
  /** What the chain collides with (see DynamicBoneColliders). */
130
- colliders: DynamicBoneColliders;
186
+ get colliders(): DynamicBoneColliders;
187
+ set colliders(v: DynamicBoneColliders);
188
+ private _side;
131
189
  /** The cloth's outside — makes the colliders one-sided (see DynamicBoneSide). */
132
- side: DynamicBoneSide;
190
+ get side(): DynamicBoneSide;
191
+ set side(v: DynamicBoneSide);
192
+ private _guideHold;
133
193
  /** How firmly `guide()` targets are HELD through the constraint passes, 0..1. At 0 a guide is applied once
134
194
  * before the passes and the length / link passes may drag the bone back toward its un-guided neighbours
135
195
  * within the same frame; at 0.5 it is re-pulled after every pass with half its weight (converges with the
136
196
  * passes), at 1 with its full weight (a target the bone length cannot reach then jitters). */
137
- guideHold: number;
197
+ get guideHold(): number;
198
+ set guideHold(v: number);
199
+ private _edges;
138
200
  /** The chain's EDGES collide with the capsules too — every bone segment and every link, not only the bones'
139
201
  * particles: a capsule thinner than a bone's length (a forearm) no longer passes through the cloth between
140
202
  * two bones. Off = particles only. */
141
- edges: boolean;
203
+ get edges(): boolean;
204
+ set edges(v: boolean);
142
205
  static fields: FieldMeta<DynamicBone>;
143
206
  private _id;
144
207
  private _chain;
@@ -154,9 +217,10 @@ export declare class DynamicBone extends Aspect<"dynamicBone", Node> {
154
217
  /** The bones of the chain, the root first. */
155
218
  get chain(): readonly Node[];
156
219
  onAttach(): void;
157
- onReconfigure(): void;
158
- /** Every field is live: what changed since the last frame is pushed here, before the engine's stage. */
159
- update(): void;
220
+ /** Every field is live: a write marks the chain dirty and what changed is pushed here, once, before
221
+ * the next step (the floor and the collider list are each keyed, so a point written every frame
222
+ * costs one compare). */
223
+ protected flush(): void;
160
224
  onDetach(): void;
161
225
  /** Snap the chain onto the animated pose next frame (a teleport, a camera cut). */
162
226
  reset(): void;
@@ -21,7 +21,6 @@ declare abstract class Chain<Name extends string> extends Aspect<Name, Node> {
21
21
  get error(): number;
22
22
  onAttach(): void;
23
23
  onDetach(): void;
24
- onReconfigure(): void;
25
24
  protected params(): Float32Array;
26
25
  /** Push the description to the engine (a no-op until attached). */
27
26
  protected abstract push(): void;
@@ -68,7 +68,6 @@ export declare class NavAgent extends Aspect<"agent", Node, NavAgentEvents> {
68
68
  private _target;
69
69
  /** velocity-driven (`move`) rather than target-driven */
70
70
  private _steering;
71
- private _dirty;
72
71
  private _faceX;
73
72
  private _faceZ;
74
73
  private _retryAt;
@@ -77,7 +76,9 @@ export declare class NavAgent extends Aspect<"agent", Node, NavAgentEvents> {
77
76
  private _near;
78
77
  private _slow;
79
78
  onAttach(): void;
80
- onReconfigure(): void;
79
+ /** A parameter changed: push the agent's params to the crowd (a no-op until it has a slot —
80
+ * `_join` sends them with the add). */
81
+ protected flush(): void;
81
82
  onDetach(): void;
82
83
  /** Walk to a point. False = no walkable polygon near it (or no navmesh) — the current target stays. */
83
84
  goTo(target: Vec3Like): boolean;
@@ -45,11 +45,10 @@ export declare class Physics extends Aspect<"physics", Node> implements CompWrit
45
45
  * `1`, ice `0.02`. A Vehicle's tires read the GROUND body's value, so this is the single number
46
46
  * that decides how well a car corners.
47
47
  *
48
- * Change it at runtime by re-configuring — `floor.aspect(Physics, { friction: 0.02 })` (an ice
49
- * patch) — or by assigning `floor.physics.friction = 0.02`; either way the setter pushes the new
50
- * surface to the live body at once. (chisel keeps an instance setter whose name appears as an
51
- * object-literal key anywhere in the bundle, so the config-object route survives tree-shaking
52
- * even when no code reads `.friction`.)
48
+ * Live: `floor.physics.friction = 0.02` (an ice patch) pushes the new surface to the body at
49
+ * once. (chisel keeps an instance setter whose name appears as an object-literal key anywhere in
50
+ * the bundle, so `aspect(Physics, { friction })` at build survives tree-shaking even when no code
51
+ * reads `.friction`.)
53
52
  */
54
53
  get friction(): number;
55
54
  set friction(v: number);
@@ -1,4 +1,5 @@
1
1
  import { Aspect } from "../../core/Aspect";
2
+ import type { FieldMeta } from "../../core/fields";
2
3
  import { type Vec3Like } from "../../math/vec";
3
4
  import type { Node } from "../Node";
4
5
  /** Which geometry a Shape uses — the one-of the fields below encode (see `_build`'s order). */
@@ -26,29 +27,49 @@ export type ShapeFit = {
26
27
  };
27
28
  export declare class Shape extends Aspect<"shape", Node> {
28
29
  static readonly aspect = "shape";
30
+ private _box?;
31
+ private _sphere?;
32
+ private _cylinder?;
33
+ private _capsule?;
34
+ private _mesh?;
35
+ private _heightfield?;
36
+ private _origin?;
37
+ private _raycast;
29
38
  /** Box half-extents [hx, hy, hz] (world units). */
30
- box?: Vec3Like;
39
+ get box(): Vec3Like | undefined;
40
+ set box(v: Vec3Like | undefined);
31
41
  /** Sphere radius. */
32
- sphere?: number;
42
+ get sphere(): number | undefined;
43
+ set sphere(v: number | undefined);
33
44
  /** Cylinder aligned on Y: half-height + radius. */
34
- cylinder?: {
45
+ get cylinder(): {
35
46
  halfHeight: number;
36
47
  radius: number;
37
- };
48
+ } | undefined;
49
+ set cylinder(v: {
50
+ halfHeight: number;
51
+ radius: number;
52
+ } | undefined);
38
53
  /** Capsule aligned on Y: half-height of the cylinder section + radius. */
39
- capsule?: {
54
+ get capsule(): {
40
55
  halfHeight: number;
41
56
  radius: number;
42
- };
57
+ } | undefined;
58
+ set capsule(v: {
59
+ halfHeight: number;
60
+ radius: number;
61
+ } | undefined);
43
62
  /** The node's own triangles (a Mesh's geometry or a Model's GLB, world scale applied).
44
63
  * `true` = exact triangle mesh — static/kinematic bodies, triggers, characters' ground and picking
45
64
  * only (a dynamic body can't be a triangle mesh; Physics throws). `'convex'` = convex hull of the
46
65
  * vertices, works for dynamic bodies too. A Model uses its bind pose (skinned parts skipped). */
47
- mesh?: boolean | "convex";
66
+ get mesh(): boolean | "convex" | undefined;
67
+ set mesh(v: boolean | "convex" | undefined);
48
68
  /** The node's terrain (`Terrain.create(...).node`) as a Jolt height field — the exact drawn grid,
49
69
  * holes included (docs/terrain-plan.md). Static / kinematic / picking / character ground only,
50
70
  * like `mesh: true`. `terrain.commit()` pushes edits into the live shape. */
51
- heightfield?: boolean;
71
+ get heightfield(): boolean | undefined;
72
+ set heightfield(v: boolean | undefined);
52
73
  /**
53
74
  * The shape's centre, relative to the node's origin — world units in the node's ROTATED frame
54
75
  * (the node's scale is ignored, exactly like the explicit dimensions above). Default [0, 0, 0].
@@ -62,20 +83,24 @@ export declare class Shape extends Aspect<"shape", Node> {
62
83
  * you would expect. With no `origin` an auto shape (`{}`) still centres itself on the node's own
63
84
  * mesh bounds — only explicit dimensions sit on the pivot by default.
64
85
  */
65
- origin?: Vec3Like;
66
- /** Whether pointer rays can hit this shape (click / touchstart). Default true. */
67
- raycast: boolean;
86
+ get origin(): Vec3Like | undefined;
87
+ set origin(v: Vec3Like | undefined);
88
+ /** Whether pointer rays can hit this shape (click / touchstart). Default true. Live, at once. */
89
+ get raycast(): boolean;
90
+ set raycast(v: boolean);
91
+ /** Scene-editor inspector: the geometry fields (accessors, so they are listed here by name). */
92
+ static fields: FieldMeta<Shape>;
68
93
  private _shapeId;
69
94
  private _bodyId;
70
95
  /** Centre the "auto" box measured for itself — used when `origin` isn't set explicitly. */
71
96
  private _autoOrigin;
72
- /** Geometry props as of the last build (see onReconfigure). */
97
+ /** Geometry props as of the last build (see _changed). */
73
98
  private _sig;
74
99
  onAttach(): void;
75
100
  onDetach(): void;
76
- /** Re-configuring (`node.aspect(Shape, { origin })`) rebuilds the geometry when a dimension, the
77
- * kind or the origin changed, and re-applies pickability. The body keeps its id and velocity. */
78
- onReconfigure(): void;
101
+ /** A dimension, the kind or the origin was written: rebuild the geometry when it actually changed.
102
+ * The body keeps its id and velocity. */
103
+ private _changed;
79
104
  /**
80
105
  * Measure the node's rendered geometry and size the collider to it — the code half of the scene
81
106
  * editor's "Fit to mesh". Keeps the current kind unless one is passed; `auto` becomes an explicit