incanto 0.74.0 → 0.75.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.
Files changed (92) hide show
  1. package/bin/incanto-multiplay.mjs +52 -4
  2. package/dist/2d.d.ts +83 -7
  3. package/dist/2d.js +4 -3
  4. package/dist/3d.d.ts +743 -167
  5. package/dist/3d.js +6 -6
  6. package/dist/{agent8-CHTT4unP.js → agent8-B-bh3n0X.js} +1 -1
  7. package/dist/{audio-player-BOrk4eQx.d.ts → audio-player-BRo2uvG6.d.ts} +23 -2
  8. package/dist/{behavior-J1cmVah0.d.ts → behavior-B_245qRy.d.ts} +15 -1
  9. package/dist/{create-game-BAiA-FjP.js → create-game-DVUhHs2B.js} +79 -10
  10. package/dist/{create-game-ssvGvP7W.js → create-game-DnwhJ5nW.js} +83 -7
  11. package/dist/debug.d.ts +1 -1
  12. package/dist/{editor-switch-CFU9mCec.d.ts → editor-switch-O8mxpgRX.d.ts} +1 -1
  13. package/dist/editor.js +1600 -1529
  14. package/dist/env.d.ts +1 -1
  15. package/dist/{environment-presets-BkqlWewf.js → environment-presets-BP77Dl0K.js} +2005 -60
  16. package/dist/{gameplay-Bxe1sMVT.js → gameplay-D-JuGura.js} +9309 -6595
  17. package/dist/gameplay.d.ts +573 -31
  18. package/dist/gameplay.js +3 -2
  19. package/dist/index.d.ts +150 -6
  20. package/dist/index.js +6 -6
  21. package/dist/{loader-BAeWMYfF.d.ts → loader-CbkVdXL8.d.ts} +2 -2
  22. package/dist/net.d.ts +2 -2
  23. package/dist/net.js +2 -2
  24. package/dist/{physics-2d-C-SfvjzH.js → physics-2d-x3bCrQf0.js} +250 -31
  25. package/dist/{physics-3d-rOzeg890.js → physics-3d-Bz2VPQ6D.js} +673 -51
  26. package/dist/{picking-BMV34Pjl.js → picking-Buita5T9.js} +2 -2
  27. package/dist/{save-slots-CEUGeLuB.js → pose-ByFB_J3O.js} +217 -11
  28. package/dist/react.d.ts +2 -2
  29. package/dist/react.js +1 -1
  30. package/dist/{register-CjociOtt.js → register-B768Qedj.js} +596 -2
  31. package/dist/{register-DRQyZKGU.js → register-DxAbTO2T.js} +191 -430
  32. package/dist/{replay-B6BbgGM_.js → replay-DrqQ6dZj.js} +133 -18
  33. package/dist/{replay-wZK5Ok5c.d.ts → replay-W5nCw_cU.d.ts} +21 -2
  34. package/dist/{rng-Bb-IutXB.d.ts → rng-BsXZg3D6.d.ts} +7 -0
  35. package/dist/{split-screen-BxZ5rBe7.js → split-screen-B-dIcQsQ.js} +10 -5
  36. package/dist/{split-screen-D6sx8z3Z.d.ts → split-screen-CiLJf2-C.d.ts} +3 -3
  37. package/dist/{sprite-animation-Bz3DHD_4.js → sprite-animation-SQa5gIu2.js} +8 -6
  38. package/dist/{src-CqtvYtSN.js → src-DLKVc6Hj.js} +1 -1
  39. package/dist/{test-CEl0y2Sw.js → test-HlVUeCSn.js} +487 -82
  40. package/dist/test.d.ts +90 -12
  41. package/dist/test.js +2 -2
  42. package/dist/vite.js +3 -3
  43. package/editor/assets/{agent8-BlzturGi.js → agent8-BXlYM9rv.js} +1 -1
  44. package/editor/assets/{debug-BMUi8usj.js → debug-S42XGP4Y.js} +1 -1
  45. package/editor/assets/index-DgrgUKno.js +11046 -0
  46. package/editor/index.html +1 -1
  47. package/package.json +1 -1
  48. package/schemas/scene.schema.json +1630 -299
  49. package/skills/incanto-3d-character.md +358 -20
  50. package/skills/incanto-audio.md +24 -2
  51. package/skills/incanto-building-2d-games.md +21 -2
  52. package/skills/incanto-building-3d-games.md +38 -3
  53. package/skills/incanto-editor.md +17 -6
  54. package/skills/incanto-environment.md +227 -2
  55. package/skills/incanto-game-feel.md +60 -1
  56. package/skills/incanto-gameplay-behaviors.md +668 -20
  57. package/skills/incanto-hud.md +116 -0
  58. package/skills/incanto-multiplayer.md +141 -2
  59. package/skills/incanto-node-reference.md +393 -16
  60. package/skills/incanto-performance.md +32 -0
  61. package/skills/incanto-physics-and-input.md +241 -13
  62. package/skills/incanto-playtesting.md +2 -2
  63. package/skills/incanto-save-slots.md +61 -2
  64. package/skills/incanto-scene-json-authoring.md +13 -0
  65. package/skills/incanto-verifying-your-game.md +86 -3
  66. package/templates-app/beacon-isle-3d/PROJECT/Status.md +12 -0
  67. package/templates-app/beacon-isle-3d/package.json +1 -1
  68. package/templates-app/beacon-isle-3d/src/game.scene.json +151 -2
  69. package/templates-app/molehill-2d/PROJECT/Status.md +7 -0
  70. package/templates-app/molehill-2d/package.json +1 -1
  71. package/templates-app/molehill-2d/src/game.scene.json +129 -2
  72. package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
  73. package/templates-app/platformer-2d/docs/project-2d-rules.md +3 -2
  74. package/templates-app/platformer-2d/package.json +1 -1
  75. package/templates-app/platformer-2d/src/behaviors.ts +40 -26
  76. package/templates-app/platformer-2d/src/game.scene.json +144 -2
  77. package/templates-app/platformer-2d/verify.ts +18 -1
  78. package/templates-app/star-survivor/PROJECT/Status.md +7 -0
  79. package/templates-app/star-survivor/package.json +1 -1
  80. package/templates-app/star-survivor/src/behaviors.ts +9 -8
  81. package/templates-app/star-survivor/src/game.scene.json +142 -4
  82. package/templates-app/star-survivor/verify.ts +13 -0
  83. package/templates-app/tps-3d/PROJECT/Status.md +6 -0
  84. package/templates-app/tps-3d/package.json +1 -1
  85. package/templates-app/tps-3d/src/game.scene.json +71 -10
  86. package/templates-app/village-quest-3d/PROJECT/Status.md +7 -0
  87. package/templates-app/village-quest-3d/package.json +1 -1
  88. package/templates-app/village-quest-3d/src/behaviors.ts +8 -16
  89. package/templates-app/village-quest-3d/src/grove.scene.json +121 -5
  90. package/templates-app/village-quest-3d/src/village.scene.json +126 -2
  91. package/templates-app/village-quest-3d/verify.ts +52 -2
  92. package/editor/assets/index-CrUCQoaB.js +0 -11046
package/dist/3d.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-BOrk4eQx.js";
2
- import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-J1cmVah0.js";
1
+ import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-BRo2uvG6.js";
2
+ import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-B_245qRy.js";
3
3
  import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
4
- import { a as SceneJson$1, s as JsonObject } from "./rng-Bb-IutXB.js";
5
- import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
4
+ import { a as SceneJson$1, s as JsonObject } from "./rng-BsXZg3D6.js";
5
+ import { t as EditorSwitchOptions } from "./editor-switch-O8mxpgRX.js";
6
6
  import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DNxDAb1w.js";
7
- import { t as LoadSceneOptions } from "./loader-BAeWMYfF.js";
7
+ import { t as LoadSceneOptions } from "./loader-CbkVdXL8.js";
8
8
  import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
9
- import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
9
+ import { AnimationClip, AnimationMixer, BufferGeometry, Color, DataTexture, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Quaternion, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
10
10
  import { VRM } from "@pixiv/three-vrm";
11
11
  import { Sky } from "three/examples/jsm/objects/Sky.js";
12
12
  import * as RapierNs from "@dimforge/rapier3d-compat";
@@ -451,6 +451,17 @@ declare class RigidBody3D extends PhysicsBody3D {
451
451
  friction: number;
452
452
  restitution: number;
453
453
  /**
454
+ * How much a `Water3D` lifts this body: `0` (default) = it falls through
455
+ * water like air, `1` = water's own upthrust — the submerged part of the
456
+ * collider's volume, at 1000 kg/m³. So `mass` against the collider decides:
457
+ * a 1 m³ crate at 200 kg floats a fifth under, at 3000 kg it sinks, and a
458
+ * heavier hull sits deeper. Eight sample points across the collider give a
459
+ * tilted hull a righting moment, and the water's `drag` slows it. A body with
460
+ * a `CharacterController3D` under it is never lifted here — the swim spring
461
+ * owns that one.
462
+ */
463
+ buoyancy: number;
464
+ /**
454
465
  * Drag, per second: velocity decays by `e^(-linearDamping·t)`. `0` = none.
455
466
  * A body flying through nothing keeps its speed forever otherwise.
456
467
  */
@@ -494,6 +505,16 @@ declare class CharacterBody3D extends PhysicsBody3D {
494
505
  /** m/s, y-up (up = +y). */
495
506
  velocity: number[];
496
507
  /**
508
+ * The mass this body pushes dynamic bodies with, in kg. Rapier's character
509
+ * controller treats every dynamic body as an OBSTACLE — a character walks
510
+ * around things — so a beam on a `Patrol` slid up to the player and stopped
511
+ * dead against them, forever. A piston, a sweeping arm, a moving wall or a
512
+ * bruiser enemy is a thing that shoves: give it a mass and it pushes what it
513
+ * meets, and the harder the heavier. `0` (the default) keeps every scene as
514
+ * it was.
515
+ */
516
+ pushes: number;
517
+ /**
497
518
  * Hold the capsule against the surface while it moves, so walking down a
498
519
  * slope does not become a series of small falls.
499
520
  *
@@ -577,6 +598,94 @@ declare class CharacterBody3D extends PhysicsBody3D {
577
598
  isOnFloor(): boolean;
578
599
  }
579
600
  //#endregion
601
+ //#region src/3d/nodes/vehicle-3d.d.ts
602
+ /** One wheel, as authored in `wheels`. */
603
+ interface WheelSpec {
604
+ /** Where the spring hangs from, in the CHASSIS's frame (m). */
605
+ position: [number, number, number];
606
+ /** Tyre radius (m). */
607
+ radius: number;
608
+ /** Spring length at rest (m) — the wheel hangs this far below its mount, less the load. */
609
+ rest: number;
610
+ /** Turns with the steer. */
611
+ steer: boolean;
612
+ /** Takes the engine force. */
613
+ drive: boolean;
614
+ }
615
+ /** What one wheel is doing this step. */
616
+ interface WheelState {
617
+ /** The spring found ground. */
618
+ contact: boolean;
619
+ /** Current spring length (m) — the wheel's centre is this far below its mount. */
620
+ suspension: number;
621
+ /** Total roll, radians. */
622
+ rotation: number;
623
+ /** Current steer, radians. */
624
+ steering: number;
625
+ }
626
+ /**
627
+ * A car in one node — Rapier's raycast vehicle under a `RigidBody3D` chassis.
628
+ *
629
+ * ```json
630
+ * { "name": "Car", "type": "RigidBody3D",
631
+ * "props": { "mass": 800, "collider": { "shape": "box", "size": [1.8, 0.6, 4] } },
632
+ * "children": [
633
+ * { "name": "Drive", "type": "Vehicle3D", "props": { "wheels": [
634
+ * { "position": [-0.8, -0.1, 1.4], "steer": true },
635
+ * { "position": [ 0.8, -0.1, 1.4], "steer": true },
636
+ * { "position": [-0.8, -0.1, -1.4], "drive": true },
637
+ * { "position": [ 0.8, -0.1, -1.4], "drive": true } ] } },
638
+ * { "name": "Wheel0", "type": "Node3D", "props": { "position": [-0.8, -0.1, 1.4] },
639
+ * "children": [ { "name": "Hub", "type": "Node3D", "children": [ …the tyre mesh… ] } ] }
640
+ * ] }
641
+ * ```
642
+ *
643
+ * The wheels are springs that never touch anything (a ray each), so a car
644
+ * cannot catch a kerb on a wheel body or disagree with its axle; the throttle,
645
+ * steer and brake come from the `move` vector and the `brake` button (or from
646
+ * code, with `moveAction: ""`). Forward is +z, the +Z-forward rule. A child
647
+ * named `Wheel<i>` is posed every step — it hangs on its spring and turns to
648
+ * steer — and its child `Hub` spins as the wheel rolls.
649
+ */
650
+ declare class Vehicle3D extends Node3D {
651
+ static override readonly typeName: string;
652
+ static override readonly props: PropSchema;
653
+ wheels: WheelSpec[];
654
+ suspensionStiffness: number;
655
+ suspensionCompression: number;
656
+ suspensionRelaxation: number;
657
+ maxTravel: number;
658
+ friction: number;
659
+ sideFriction: number;
660
+ maxSteerDeg: number;
661
+ engineForce: number;
662
+ brakeForce: number;
663
+ moveAction: string;
664
+ brakeAction: string;
665
+ enabled: boolean;
666
+ /** Live inputs, −1..1 (throttle, steer) and 0..1 (brake) — the actions write these, or your code does. */
667
+ throttle: number;
668
+ steer: number;
669
+ brake: number;
670
+ /** Forward speed, m/s (negative in reverse). */
671
+ speed: number;
672
+ /** @internal Written by the physics adapter each step. */
673
+ _states: WheelState[];
674
+ private reportedActions;
675
+ /** What wheel `i` is doing. */
676
+ wheel(i: number): WheelState;
677
+ /** The wheels with every default filled in. */
678
+ specs(): WheelSpec[];
679
+ get body(): RigidBody3D;
680
+ override onEnterTree(): void;
681
+ override onExitTree(): void;
682
+ override fixedUpdate(dt: number): void;
683
+ /** `Wheel<i>` hangs on its spring and turns to steer; its `Hub` spins. */
684
+ private poseWheels;
685
+ /** Full lock, radians. */
686
+ get maxSteer(): number;
687
+ }
688
+ //#endregion
580
689
  //#region src/3d/physics/physics-3d.d.ts
581
690
  type Rapier = typeof RapierNs;
582
691
  interface Physics3DOptions {
@@ -616,6 +725,11 @@ declare class Physics3D {
616
725
  private readonly warnedNoCollider;
617
726
  private readonly entries;
618
727
  private readonly byColliderHandle;
728
+ /** Every Water3D in the tree, rescanned when the structure changes. */
729
+ private readonly waters;
730
+ private watersStale;
731
+ /** Raycast vehicles, one per Vehicle3D in the tree, on their chassis entries. */
732
+ private readonly vehicles;
619
733
  private readonly world;
620
734
  private readonly events;
621
735
  private readonly kcc;
@@ -639,6 +753,15 @@ declare class Physics3D {
639
753
  * down to the places where that pair disagrees with a rotated parent.
640
754
  */
641
755
  private poseFromTree;
756
+ /**
757
+ * @internal Called by Vehicle3D.fixedUpdate: push the throttle, steer and
758
+ * brake into Rapier's raycast vehicle on the chassis and let it apply the
759
+ * step's forces; read the wheels back. The controller is made on first
760
+ * use and remade if the chassis body was rebuilt.
761
+ */
762
+ _driveVehicle(node: Vehicle3D, dt: number): void;
763
+ /** @internal The Vehicle3D left the tree: drop its controller. */
764
+ _freeVehicle(node: Vehicle3D): void;
642
765
  /** @internal Called by CharacterBody3D.moveAndSlide (during tree fixedUpdate). */
643
766
  /**
644
767
  * May `candidate` carry `rider`? — see the 2D twin.
@@ -662,6 +785,28 @@ declare class Physics3D {
662
785
  private lastRoot;
663
786
  private readonly jointSet;
664
787
  private readonly joints;
788
+ /** The two bodies each live joint ties, so a departed joint can be unlinked. */
789
+ private readonly jointBodies;
790
+ /** What a hinge's limits/motor were last pushed as, so a write re-applies. */
791
+ private readonly hingeState;
792
+ /** Joints refused at creation (bodies that disagree about the axis) — said once. */
793
+ private readonly refusedJoints;
794
+ /** A rope's or spring's numbers as last made, so a write REMAKES the joint. */
795
+ private readonly tetherState;
796
+ private tetherKey;
797
+ /**
798
+ * Who is jointed to whom, and whether that pair's contacts are on.
799
+ *
800
+ * A joint's own bodies are not the world to the character controller: a
801
+ * body jointed to a character with its contacts off is not an obstacle to
802
+ * its shape-cast (the joint said so, for the contact solver; the cast asks
803
+ * its own question), and a body jointed to it is never its GROUND — a
804
+ * chain hanging from a crane hook was the hook's "moving platform", and the
805
+ * carry dragged the hook along by however far the hook had just moved.
806
+ */
807
+ private readonly jointed;
808
+ private linkJointed;
809
+ private unlinkJointed;
665
810
  /** One fixed body per solid scatter field, carrying a collider per row. */
666
811
  private readonly scatterBodies;
667
812
  private readonly bodySet;
@@ -714,15 +859,41 @@ declare class Physics3D {
714
859
  * meantime. syncBodies runs every step, so the body appears the moment the
715
860
  * download lands.
716
861
  */
862
+ /**
863
+ * Lift every buoyant dynamic body by the water it is in — before the solver
864
+ * step, so the impulses are part of this step's motion.
865
+ *
866
+ * `Water3D.heightAt` had answered "so gameplay can float a raft, bob a
867
+ * buoy" since the water shipped, and nothing floated anything but the
868
+ * swimmer: a RigidBody3D dropped into a lake fell through it to the bed,
869
+ * whatever it weighed. This is Archimedes on eight sample points: each
870
+ * octant of the collider is an eighth of its volume, lifted by the water's
871
+ * density times however much of it is under the surface AT THAT POINT, at
872
+ * that point — so a tilted hull's low corners push harder and it rights
873
+ * itself, and a wave under one end rocks it. The water's `drag` then bleeds
874
+ * velocity and spin in proportion to how much is under, which is what stops
875
+ * a pushed crate and lets a bob die out.
876
+ */
877
+ private applyBuoyancy;
878
+ /** The water whose footprint covers world (x, z), or null. */
879
+ private waterAt;
717
880
  private ensureEntry;
718
881
  /** Apply a world-space impulse to a dynamic body (character controllers). */
719
882
  applyImpulse(node: PhysicsBody3D, impulse: [number, number, number]): void;
720
883
  /** Mass the solver actually uses (collider-derived unless overridden). */
721
884
  massOf(node: PhysicsBody3D): number;
885
+ /** The solver's rotation of a body, as a quaternion `[x, y, z, w]`. */
886
+ rotationOf(node: PhysicsBody3D): [number, number, number, number];
722
887
  /** Current solver velocity (fresher than the node prop mid-step). */
723
888
  velocityOf(node: PhysicsBody3D): [number, number, number];
724
889
  /** Create newly-arrived joints; tear down departed ones. */
725
890
  private syncJoints;
891
+ /**
892
+ * Push a hinge's `limits` and motor to the solver — on creation, and again
893
+ * whenever either changes. Limits and `angle` are this body relative to the
894
+ * target; Rapier measures the other way round, hence the flip.
895
+ */
896
+ private applyHinge;
726
897
  /** Who is currently inside each sensor/body, maintained from the event drain. */
727
898
  private readonly overlaps;
728
899
  private trackOverlap;
@@ -835,6 +1006,19 @@ interface CreateGame3DOptions {
835
1006
  * to development, e.g. `debug: import.meta.env.VITE_INCANTO_DEBUG === '1'`.
836
1007
  */
837
1008
  debug?: boolean;
1009
+ /**
1010
+ * Start the frame loop as soon as the game is built (default `true`).
1011
+ *
1012
+ * `false` hands back a game that has not run a single frame: no
1013
+ * `engine.start()`, and no warm-up tick either. Call `game.engine.start()`
1014
+ * when everything that must exist BEFORE the first frame does — a
1015
+ * `NetworkManager`, whose join takes a moment during which every behaviour
1016
+ * would otherwise run the game OFFLINE. The first race built from the
1017
+ * tarball gridded itself to slot 0 in those frames and sent that pose as
1018
+ * its first replicated state, on top of the other player's car. The shader
1019
+ * warm-up still runs; the canvas stays blank until you start.
1020
+ */
1021
+ autoStart?: boolean;
838
1022
  /** @internal Test seam — replaces `document` for the debug overlay. */
839
1023
  _debugDoc?: {
840
1024
  createElement(tag: string): HTMLElement;
@@ -1465,6 +1649,16 @@ declare class BoneLookAt3D extends Node3D {
1465
1649
  private lookedUpFor;
1466
1650
  /** 0..1 engage blend — eases in/out so tracking never snaps. */
1467
1651
  private engage;
1652
+ /**
1653
+ * How far the head is COMMITTED to the target, 0..1.
1654
+ *
1655
+ * `attachedBone` was a test hook for "did it find the bone"; this is the one
1656
+ * for "is it watching" — the whole observable effect of the node, and it eased
1657
+ * in and out where nothing could read it. A harness asking whether an NPC
1658
+ * tracks the player, and lets go when the player walks behind it, has no other
1659
+ * question to ask.
1660
+ */
1661
+ get engaged(): number;
1468
1662
  /** Test hook. */
1469
1663
  get attachedBone(): Object3D | null;
1470
1664
  _onRender3D(_ctx: RenderContext3D): void;
@@ -1482,9 +1676,20 @@ declare class Camera3D extends Node3D {
1482
1676
  /** A frustum whose planes are the wrong way round draws nothing at all. */
1483
1677
  static validateJson(node: Node): void;
1484
1678
  fov: number;
1679
+ minHorizontalFov: number;
1485
1680
  near: number;
1486
1681
  far: number;
1487
1682
  current: boolean;
1683
+ /**
1684
+ * Make THIS the scene's camera and no other: the renderer takes the first
1685
+ * camera whose `current` is true in tree order, so setting your own without
1686
+ * clearing the gameplay camera's changed nothing visible. A handler a
1687
+ * connection can name — `triggerEnter → DoorCam.makeCurrent`.
1688
+ */
1689
+ makeCurrent(blendSeconds?: number | undefined): void;
1690
+ blendSeconds: number;
1691
+ /** @internal `makeCurrent(seconds)` — read once by the renderer's sync. */
1692
+ _blendRequest: number | undefined;
1488
1693
  lookAt: string;
1489
1694
  /**
1490
1695
  * Aim, every frame, whenever `lookAt` names something — see `aimAt`, which
@@ -1494,6 +1699,15 @@ declare class Camera3D extends Node3D {
1494
1699
  private warnedLookAt;
1495
1700
  override update(_dt: number): void;
1496
1701
  protected override _createObject3D(): Object3D;
1702
+ /**
1703
+ * The vertical fov to actually render with at this aspect.
1704
+ *
1705
+ * Plain `fov` unless `minHorizontalFov` asks for more width than the screen
1706
+ * carries, in which case it is widened until it does. Public because a game
1707
+ * that wants to know what it is really showing — a harness, a debug overlay —
1708
+ * could not otherwise ask, and the answer is not the authored number.
1709
+ */
1710
+ viewFov(aspect: number): number;
1497
1711
  override _syncObject3D(): void;
1498
1712
  }
1499
1713
  //#endregion
@@ -1502,7 +1716,7 @@ declare class Camera3D extends Node3D {
1502
1716
  * The states this controller enters, and therefore the only keys its
1503
1717
  * `animations` map may carry.
1504
1718
  */
1505
- declare const MOVEMENT_STATES: readonly ["idle", "walk", "run", "fastRun", "airborne"];
1719
+ declare const MOVEMENT_STATES: readonly ["idle", "walk", "run", "fastRun", "airborne", "swim", "climb", "crouch", "sneak", "dash"];
1506
1720
  /** One of {@link MOVEMENT_STATES}. */
1507
1721
  type MovementState = (typeof MOVEMENT_STATES)[number];
1508
1722
  /**
@@ -1517,6 +1731,7 @@ declare class CharacterController3D extends Node3D {
1517
1731
  static override readonly typeName: string;
1518
1732
  static override readonly signals: readonly string[];
1519
1733
  static override readonly props: PropSchema;
1734
+ enabled: boolean;
1520
1735
  view: RigView;
1521
1736
  camDistance: number;
1522
1737
  eyeHeight: number;
@@ -1543,6 +1758,50 @@ declare class CharacterController3D extends Node3D {
1543
1758
  fallGravity: number;
1544
1759
  floatHeight: number;
1545
1760
  /**
1761
+ * Swimming pace in water too deep to stand in (m/s; `sprint` still
1762
+ * multiplies). `0` turns swimming OFF and the body sinks to the bed, which
1763
+ * is what a drowning pit wants and what every scene got before this.
1764
+ */
1765
+ swimSpeed: number;
1766
+ /** Where the body's origin rides below the surface while swimming (m). */
1767
+ swimDepth: number;
1768
+ /** Held: swim down at `swimSpeed`. Missing from the input map is fine. */
1769
+ diveAction: string;
1770
+ /**
1771
+ * Ladder pace (m/s). A ladder is any `Area3D` in `ladderGroup`: push UP into
1772
+ * it and the body climbs, gravity off, held to the rungs; at the top it
1773
+ * pulls itself onto the ledge, down steps off at the bottom, `jump` lets go.
1774
+ * `0` = no ladders (every scene before this).
1775
+ */
1776
+ climbSpeed: number;
1777
+ ladderGroup: string;
1778
+ /**
1779
+ * The pull-up, for any jump. A jump that falls a hand short of a ledge is
1780
+ * the most common near-miss in a platformer, and every one handles it the
1781
+ * same way: catch the edge, pull up. On the way down from a jump, a ledge
1782
+ * ahead no higher than this above the capsule's bottom is taken — the same
1783
+ * climb that takes a swimmer out of the water and a climber off a ladder.
1784
+ * `0` (the default) = a jump near a wall feels exactly as it did.
1785
+ */
1786
+ mantleHeight: number;
1787
+ crouchHeight: number;
1788
+ crouchSpeedMultiplier: number;
1789
+ crouchAction: string;
1790
+ dashSpeed: number;
1791
+ dashSeconds: number;
1792
+ dashCooldown: number;
1793
+ dashAction: string;
1794
+ dashBackstep: boolean;
1795
+ private dashLeft;
1796
+ private dashCooldownLeft;
1797
+ private dashDir;
1798
+ /** Read-only: shorter right now — by the key, or by a ceiling. */
1799
+ crouching: boolean;
1800
+ /** The capsule height to stand back up to. */
1801
+ private standingHeight;
1802
+ /** The skin's authored y offset, restored on standing. */
1803
+ private skinRest;
1804
+ /**
1546
1805
  * How high a step the PLAYER walks up without jumping (0 = off).
1547
1806
  *
1548
1807
  * The hover spring holds the capsule a fixed distance above whatever is
@@ -1566,8 +1825,10 @@ declare class CharacterController3D extends Node3D {
1566
1825
  zoomMax: number;
1567
1826
  pitchMin: number;
1568
1827
  pitchMax: number;
1828
+ pitchStart: number;
1569
1829
  /** Spring-arm: pull the orbit camera in front of walls/ground instead of clipping. */
1570
1830
  cameraCollision: boolean;
1831
+ camera: "drive" | "none";
1571
1832
  /**
1572
1833
  * Ride whatever you are standing on.
1573
1834
  *
@@ -1592,6 +1853,8 @@ declare class CharacterController3D extends Node3D {
1592
1853
  * would fling the player on every step onto one.
1593
1854
  */
1594
1855
  private groundCarry;
1856
+ private carriedRot;
1857
+ private carriedMe;
1595
1858
  turnSpeed: number;
1596
1859
  /** Camera smoothing rate (1-exp(-rate·dt)); side view uses 5. */
1597
1860
  camLerp: number;
@@ -1606,6 +1869,19 @@ declare class CharacterController3D extends Node3D {
1606
1869
  * character facing away from the camera until it first moves).
1607
1870
  */
1608
1871
  skinYawOffset: number;
1872
+ lockOnAction: string;
1873
+ lockGroup: string;
1874
+ lockRange: number;
1875
+ /** What the character is locked onto, or null. */
1876
+ lockTarget: Node | null;
1877
+ /** Lock onto `node`: the camera yaw and the skin follow it from now on. */
1878
+ lock(node: Node): void;
1879
+ /** Let go. */
1880
+ unlock(): void;
1881
+ /** Lock the nearest live, visible member of `lockGroup` within `lockRange` — or let go if locked. */
1882
+ toggleLock(): void;
1883
+ /** Player → target on the ground plane, unit; null when not locked (and lets go when the lock is stale). */
1884
+ private lockDirection;
1609
1885
  /**
1610
1886
  * Movement-state → animation asset map, applied to the `skinPath` model
1611
1887
  * directly — no CharacterAnimator behavior needed:
@@ -1628,9 +1904,29 @@ declare class CharacterController3D extends Node3D {
1628
1904
  /** Camera yaw/pitch in radians (mouse look mutates these). */
1629
1905
  yaw: number;
1630
1906
  pitch: number;
1631
- /** idle | walk | run | fastRun | airborne — drive animations from this. */
1907
+ /** idle | walk | run | fastRun | airborne | swim — drive animations from this. */
1632
1908
  state: MovementState;
1633
1909
  grounded: boolean;
1910
+ /** In water too deep to stand in — held at the surface by the swim spring. */
1911
+ swimming: boolean;
1912
+ /** The head is under the surface (diving, or a wave over it). */
1913
+ submerged: boolean;
1914
+ /** Pulling up onto a ledge out of the water (see the climb in fixedUpdate). */
1915
+ climbing: boolean;
1916
+ /** On a ladder — an `Area3D` in `ladderGroup` the body overlaps and pushed up into. */
1917
+ onLadder: boolean;
1918
+ private ladders;
1919
+ private ladderScanIn;
1920
+ private ladderLockout;
1921
+ /** Every Water3D in the tree, re-scanned every {@link WATER_SCAN_STEPS}. */
1922
+ private waters;
1923
+ private waterScanIn;
1924
+ /**
1925
+ * A hop out of the water is in progress: the spring may catch a ledge on
1926
+ * the way down (the mantle) — a jump from land never gets that, or the
1927
+ * spring would cushion every landing.
1928
+ */
1929
+ private swimHop;
1634
1930
  /** @internal Feel timers — see the jump block for what each one buys. */
1635
1931
  private coyoteLeft;
1636
1932
  private bufferLeft;
@@ -1648,6 +1944,23 @@ declare class CharacterController3D extends Node3D {
1648
1944
  /** Actions already reported missing, so a per-frame read says it once. */
1649
1945
  private readonly reportedActions;
1650
1946
  /**
1947
+ * The water over a world point — `[wave surface, still level]` — or null
1948
+ * when no `Water3D`'s footprint covers it. The tree is re-scanned once a
1949
+ * second, so a lake streamed in later is found; the wave height is the CPU
1950
+ * twin of what is drawn, so a swimmer rides the swell the way a raft does.
1951
+ */
1952
+ /** The ladder the body is overlapping, if any — an Area3D in `ladderGroup`. */
1953
+ private ladderUnder;
1954
+ /**
1955
+ * Swap the capsule's height and keep the feet where they are: the body
1956
+ * drops (or rises) by half the difference in the same step, the skin's
1957
+ * authored offset moves the other way so the model's feet stay on the
1958
+ * floor, and the adapter rebuilds the body at the new place next step.
1959
+ */
1960
+ private setHeight;
1961
+ private sceneGravity;
1962
+ private surfaceAt;
1963
+ /**
1651
1964
  * Read an input action this controller is allowed to be missing.
1652
1965
  *
1653
1966
  * Tolerated because a game may declare no sprint key and no jump; reported
@@ -1663,6 +1976,221 @@ declare class CharacterController3D extends Node3D {
1663
1976
  private findCamera;
1664
1977
  }
1665
1978
  //#endregion
1979
+ //#region src/3d/nodes/mesh-instance-3d.d.ts
1980
+ type MeshKind = "box" | "sphere" | "capsule" | "plane" | "cylinder" | "gem";
1981
+ interface MeshMaterialProps {
1982
+ color?: string;
1983
+ metalness?: number;
1984
+ roughness?: number;
1985
+ emissive?: string;
1986
+ emissiveIntensity?: number;
1987
+ wireframe?: boolean;
1988
+ /** Flat per-face shading — gives faceted meshes (gem!) crisp glints that
1989
+ * sparkle as the mesh turns, instead of a smoothed surface. */
1990
+ flatShading?: boolean;
1991
+ /** 0..1 surface opacity; below 1 turns on transparency (glassy gems, etc.). */
1992
+ opacity?: number;
1993
+ /** Depth-test against the scene (default true). Set false so the mesh ALWAYS
1994
+ * draws on top of geometry behind it — the standard trick for flat ground
1995
+ * decals (AoE telegraphs, selection rings) that must never z-fight with or be
1996
+ * occluded by bumpy terrain. Pair with a high `renderOrder`. */
1997
+ depthTest?: boolean;
1998
+ /** Write to the depth buffer (default true). Set false for additive/overlay
1999
+ * decals so they don't occlude effects drawn after them. */
2000
+ depthWrite?: boolean;
2001
+ /** 0..1 lacquer layer over the base — THE car-paint look: a glossy clear
2002
+ * coat with its own reflection on top of a metallic base. */
2003
+ clearcoat?: number;
2004
+ /** 0..1 roughness of the clearcoat layer alone (default 0 = mirror lacquer). */
2005
+ clearcoatRoughness?: number;
2006
+ /** Reflection strength from the scene's image-based lighting (the PMREM'd
2007
+ * sky / HDRI). 1 = scene default; 2+ makes glass visibly mirror the sky. */
2008
+ envMapIntensity?: number;
2009
+ /** Color texture URL (sampled sRGB, tinted by `color`). */
2010
+ map?: string;
2011
+ /** Tangent-space normal map URL (sampled linear). */
2012
+ normalMap?: string;
2013
+ /** Texture tiling [u, v] across the mesh's UVs (both maps; default [1,1]).
2014
+ * Box/plane UVs span 0–1 per face — scale repeat by the face's world size
2015
+ * for worldspace-ish texel density (e.g. a 6×2.5 m wall at one tile per
2016
+ * meter wants `repeat: [6, 2.5]`). */
2017
+ repeat?: [number, number];
2018
+ }
2019
+ /**
2020
+ * A primitive mesh. Intent-level props only:
2021
+ * - `mesh`: box | sphere | capsule | plane | cylinder | gem
2022
+ * - `size [x,y,z]`: box extents; sphere/gem radius = x; capsule radius = x,
2023
+ * height = y; plane = x·z ground plane (laid flat); cylinder radius = x, height = y
2024
+ * - `material`: `{color, metalness, roughness, wireframe, flatShading, opacity,
2025
+ * clearcoat, clearcoatRoughness, envMapIntensity, depthTest, depthWrite,
2026
+ * emissive, emissiveIntensity, map, normalMap, repeat}` —
2027
+ * `map`/`normalMap` are texture URLs loaded lazily (headless-safe: geometry and
2028
+ * physics never wait on them), tiled by `repeat: [u, v]`. `gem` + `flatShading:
2029
+ * true` + a low `roughness` reads as a sparkling faceted jewel (spin it for the
2030
+ * sparkle). `depthTest: false` makes a flat `plane`/`cylinder` an always-on-top
2031
+ * ground decal (AoE telegraph, selection ring) — no z-fighting with terrain.
2032
+ */
2033
+ declare class MeshInstance3D extends Node3D {
2034
+ static override readonly typeName: string;
2035
+ static override readonly props: PropSchema;
2036
+ mesh: string;
2037
+ size: number[];
2038
+ material: MeshMaterialProps;
2039
+ castShadow: boolean;
2040
+ receiveShadow: boolean;
2041
+ /** Loader hook: malformed materials fail at LOAD time, not at render. */
2042
+ static validateJson(node: Node): void;
2043
+ private geometryKey;
2044
+ private materialKey;
2045
+ /** True while this node is using a cache entry it must not dispose. */
2046
+ private sharedGeometry;
2047
+ private sharedMaterial;
2048
+ private textureKey;
2049
+ private loadedTextures;
2050
+ protected override _createObject3D(): Object3D;
2051
+ override _syncObject3D(alpha?: number, assets?: AssetStore3D | null): void;
2052
+ /** Lazy texture dressing — same headless guard as Tree3D bark: without a
2053
+ * DOM there is no Image decode, so geometry/colors apply and the maps are
2054
+ * skipped. Re-loads only when a texture-shaping key changes. */
2055
+ private syncTextures;
2056
+ /**
2057
+ * A private CLONE: `repeat` is per-node here (a 1x1 crate and a 8x8 floor
2058
+ * share one tile image), and that is the one field a shared master cannot
2059
+ * carry. The clone shares `texture.source`, so the fetch and the decode are
2060
+ * still done once per url for the whole scene.
2061
+ */
2062
+ private loadTexture;
2063
+ /**
2064
+ * Give the GPU back everything this node OWNS.
2065
+ *
2066
+ * It used to dispose textures and nothing else, so every freed mesh leaked its
2067
+ * geometry and its material — a wave spawner that kills and respawns fifty
2068
+ * enemies a minute leaks fifty of each, forever, and nothing in the game says
2069
+ * so. Both are built here (`_createObject3D` news them, `_syncObject3D`
2070
+ * rebuilds the geometry on a shape change), so both are ours to release.
2071
+ *
2072
+ * The textures are NOT: since the shared texture cache they belong to the
2073
+ * asset store, except the per-node clones this node asked for, which are what
2074
+ * `loadedTextures` holds.
2075
+ */
2076
+ override free(): void;
2077
+ }
2078
+ //#endregion
2079
+ //#region src/3d/nodes/instanced-mesh-3d.d.ts
2080
+ /**
2081
+ * Hundreds of copies of one mesh in ONE draw call — scattered rocks, fence
2082
+ * posts, pillars, crates, gravestones. Same `mesh`/`size`/`material` surface
2083
+ * as MeshInstance3D; `transforms` places the copies:
2084
+ *
2085
+ * { "name": "Rocks", "type": "InstancedMesh3D",
2086
+ * "props": { "mesh": "gem", "size": [0.7, 0.5, 0.7],
2087
+ * "material": { "color": "#8a8f98", "roughness": 0.9, "flatShading": true },
2088
+ * "transforms": [[12, 0.2, -8, 40, 1.3], [-6, 0.1, 14, 210, 0.8]] } }
2089
+ *
2090
+ * Each row is `[x, y, z, yawDeg?, scale?]` (yaw 0 and scale 1 when omitted) —
2091
+ * dense enough to generate hundreds inline. REPLACE the array to update
2092
+ * (mutations are not watched).
2093
+ */
2094
+ declare class InstancedMesh3D extends Node3D {
2095
+ static override readonly typeName: string;
2096
+ static override readonly props: PropSchema;
2097
+ mesh: string;
2098
+ size: number[];
2099
+ material: MeshMaterialProps;
2100
+ castShadow: boolean;
2101
+ receiveShadow: boolean;
2102
+ /**
2103
+ * Make the scatter SOLID: `{}` gives every row a collider shaped like the
2104
+ * mesh itself — a faceted `gem` stone collides as that stone's own hull, not
2105
+ * as a ball tucked inside it — sized from `size` × the row's scale.
2106
+ *
2107
+ * A field of fifty boulders a player walks straight through is the tell that
2108
+ * a world is a picture. One fixed body carries all the colliders, so the cost
2109
+ * is a handful of shapes and no per-frame work — these never move.
2110
+ *
2111
+ * `{ shape: 'sphere' | 'box' }` (with `radius`/`size`) opts out into a
2112
+ * cheaper approximation when a rough blocker is genuinely all you want.
2113
+ */
2114
+ collider: {
2115
+ shape?: string;
2116
+ radius?: number;
2117
+ size?: number[];
2118
+ } | null;
2119
+ private _transforms;
2120
+ private transformsDirty;
2121
+ get transforms(): number[][];
2122
+ set transforms(value: number[][]);
2123
+ private instanced;
2124
+ private builtKey;
2125
+ static validateJson(node: Node): void;
2126
+ /** Test hook: the live instance count. */
2127
+ get instanceCount(): number;
2128
+ override _syncObject3D(alpha?: number): void;
2129
+ override free(): void;
2130
+ }
2131
+ //#endregion
2132
+ //#region src/3d/nodes/flock-3d.d.ts
2133
+ /** One bird, in WORLD metres and m/s — what `boids()` answers. */
2134
+ interface Boid {
2135
+ x: number;
2136
+ y: number;
2137
+ z: number;
2138
+ vx: number;
2139
+ vy: number;
2140
+ vz: number;
2141
+ }
2142
+ /**
2143
+ * A flock — gulls over a harbor, fish under a boat, bats out of a cave — as
2144
+ * ONE instanced mesh that flies its own instances.
2145
+ *
2146
+ * ```json
2147
+ * { "name": "Gulls", "type": "Flock3D",
2148
+ * "props": { "position": [0, 14, 0], "count": 40, "radius": 30, "height": 6,
2149
+ * "mesh": "box", "size": [0.5, 0.08, 0.3], "follow": "/root/Boat" } }
2150
+ * ```
2151
+ *
2152
+ * Boids (Reynolds 1987): each instance steers away from neighbours closer
2153
+ * than `separation`, toward the average heading of those within `sight`
2154
+ * (`alignment`) and toward their centre (`cohesion`), turns back inside an
2155
+ * ellipsoid `radius` wide and `height` tall around this node — or around the
2156
+ * node at `follow`, offset by this node's position — and never turns faster
2157
+ * than `turn`. Every instance flies at `speed`, +z forward, so a mesh that is
2158
+ * longer along z reads as a body with a beak.
2159
+ *
2160
+ * No physics bodies, no behaviour per bird: forty birds cost one draw call
2161
+ * and forty-squared distance checks a frame. Seeded from `engine.rng`, so a
2162
+ * seeded run flies the same flight. `boids()` answers headless.
2163
+ */
2164
+ declare class Flock3D extends InstancedMesh3D {
2165
+ static override readonly typeName: string;
2166
+ static override readonly props: PropSchema;
2167
+ count: number;
2168
+ radius: number;
2169
+ height: number;
2170
+ speed: number;
2171
+ turn: number;
2172
+ separation: number;
2173
+ sight: number;
2174
+ alignment: number;
2175
+ cohesion: number;
2176
+ follow: string;
2177
+ private px;
2178
+ private py;
2179
+ private pz;
2180
+ private vx;
2181
+ private vy;
2182
+ private vz;
2183
+ private rows;
2184
+ static override validateJson(node: Node): void;
2185
+ /** Every bird right now, in world metres and m/s. */
2186
+ boids(): Boid[];
2187
+ override update(dt: number): void;
2188
+ /** The roam centre in this node's local frame: the followed node's offset, or the origin. */
2189
+ private centre;
2190
+ /** Scatter `n` birds through the bound with random headings — engine-seeded. */
2191
+ private seed;
2192
+ }
2193
+ //#endregion
1666
2194
  //#region src/3d/vegetation/flower-geometry.d.ts
1667
2195
  /**
1668
2196
  * Procedural flower PLANTS for Flowers3D — real plants like the reference
@@ -1999,161 +2527,8 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
1999
2527
  override free(): void;
2000
2528
  }
2001
2529
  //#endregion
2002
- //#region src/3d/nodes/mesh-instance-3d.d.ts
2003
- type MeshKind = "box" | "sphere" | "capsule" | "plane" | "cylinder" | "gem";
2004
- interface MeshMaterialProps {
2005
- color?: string;
2006
- metalness?: number;
2007
- roughness?: number;
2008
- emissive?: string;
2009
- emissiveIntensity?: number;
2010
- wireframe?: boolean;
2011
- /** Flat per-face shading — gives faceted meshes (gem!) crisp glints that
2012
- * sparkle as the mesh turns, instead of a smoothed surface. */
2013
- flatShading?: boolean;
2014
- /** 0..1 surface opacity; below 1 turns on transparency (glassy gems, etc.). */
2015
- opacity?: number;
2016
- /** Depth-test against the scene (default true). Set false so the mesh ALWAYS
2017
- * draws on top of geometry behind it — the standard trick for flat ground
2018
- * decals (AoE telegraphs, selection rings) that must never z-fight with or be
2019
- * occluded by bumpy terrain. Pair with a high `renderOrder`. */
2020
- depthTest?: boolean;
2021
- /** Write to the depth buffer (default true). Set false for additive/overlay
2022
- * decals so they don't occlude effects drawn after them. */
2023
- depthWrite?: boolean;
2024
- /** 0..1 lacquer layer over the base — THE car-paint look: a glossy clear
2025
- * coat with its own reflection on top of a metallic base. */
2026
- clearcoat?: number;
2027
- /** 0..1 roughness of the clearcoat layer alone (default 0 = mirror lacquer). */
2028
- clearcoatRoughness?: number;
2029
- /** Reflection strength from the scene's image-based lighting (the PMREM'd
2030
- * sky / HDRI). 1 = scene default; 2+ makes glass visibly mirror the sky. */
2031
- envMapIntensity?: number;
2032
- /** Color texture URL (sampled sRGB, tinted by `color`). */
2033
- map?: string;
2034
- /** Tangent-space normal map URL (sampled linear). */
2035
- normalMap?: string;
2036
- /** Texture tiling [u, v] across the mesh's UVs (both maps; default [1,1]).
2037
- * Box/plane UVs span 0–1 per face — scale repeat by the face's world size
2038
- * for worldspace-ish texel density (e.g. a 6×2.5 m wall at one tile per
2039
- * meter wants `repeat: [6, 2.5]`). */
2040
- repeat?: [number, number];
2041
- }
2042
- /**
2043
- * A primitive mesh. Intent-level props only:
2044
- * - `mesh`: box | sphere | capsule | plane | cylinder | gem
2045
- * - `size [x,y,z]`: box extents; sphere/gem radius = x; capsule radius = x,
2046
- * height = y; plane = x·z ground plane (laid flat); cylinder radius = x, height = y
2047
- * - `material`: `{color, metalness, roughness, wireframe, flatShading, opacity,
2048
- * clearcoat, clearcoatRoughness, envMapIntensity, depthTest, depthWrite,
2049
- * emissive, emissiveIntensity, map, normalMap, repeat}` —
2050
- * `map`/`normalMap` are texture URLs loaded lazily (headless-safe: geometry and
2051
- * physics never wait on them), tiled by `repeat: [u, v]`. `gem` + `flatShading:
2052
- * true` + a low `roughness` reads as a sparkling faceted jewel (spin it for the
2053
- * sparkle). `depthTest: false` makes a flat `plane`/`cylinder` an always-on-top
2054
- * ground decal (AoE telegraph, selection ring) — no z-fighting with terrain.
2055
- */
2056
- declare class MeshInstance3D extends Node3D {
2057
- static override readonly typeName: string;
2058
- static override readonly props: PropSchema;
2059
- mesh: string;
2060
- size: number[];
2061
- material: MeshMaterialProps;
2062
- castShadow: boolean;
2063
- receiveShadow: boolean;
2064
- /** Loader hook: malformed materials fail at LOAD time, not at render. */
2065
- static validateJson(node: Node): void;
2066
- private geometryKey;
2067
- private materialKey;
2068
- /** True while this node is using a cache entry it must not dispose. */
2069
- private sharedGeometry;
2070
- private sharedMaterial;
2071
- private textureKey;
2072
- private loadedTextures;
2073
- protected override _createObject3D(): Object3D;
2074
- override _syncObject3D(alpha?: number, assets?: AssetStore3D | null): void;
2075
- /** Lazy texture dressing — same headless guard as Tree3D bark: without a
2076
- * DOM there is no Image decode, so geometry/colors apply and the maps are
2077
- * skipped. Re-loads only when a texture-shaping key changes. */
2078
- private syncTextures;
2079
- /**
2080
- * A private CLONE: `repeat` is per-node here (a 1x1 crate and a 8x8 floor
2081
- * share one tile image), and that is the one field a shared master cannot
2082
- * carry. The clone shares `texture.source`, so the fetch and the decode are
2083
- * still done once per url for the whole scene.
2084
- */
2085
- private loadTexture;
2086
- /**
2087
- * Give the GPU back everything this node OWNS.
2088
- *
2089
- * It used to dispose textures and nothing else, so every freed mesh leaked its
2090
- * geometry and its material — a wave spawner that kills and respawns fifty
2091
- * enemies a minute leaks fifty of each, forever, and nothing in the game says
2092
- * so. Both are built here (`_createObject3D` news them, `_syncObject3D`
2093
- * rebuilds the geometry on a shape change), so both are ours to release.
2094
- *
2095
- * The textures are NOT: since the shared texture cache they belong to the
2096
- * asset store, except the per-node clones this node asked for, which are what
2097
- * `loadedTextures` holds.
2098
- */
2099
- override free(): void;
2100
- }
2101
- //#endregion
2102
- //#region src/3d/nodes/instanced-mesh-3d.d.ts
2103
- /**
2104
- * Hundreds of copies of one mesh in ONE draw call — scattered rocks, fence
2105
- * posts, pillars, crates, gravestones. Same `mesh`/`size`/`material` surface
2106
- * as MeshInstance3D; `transforms` places the copies:
2107
- *
2108
- * { "name": "Rocks", "type": "InstancedMesh3D",
2109
- * "props": { "mesh": "gem", "size": [0.7, 0.5, 0.7],
2110
- * "material": { "color": "#8a8f98", "roughness": 0.9, "flatShading": true },
2111
- * "transforms": [[12, 0.2, -8, 40, 1.3], [-6, 0.1, 14, 210, 0.8]] } }
2112
- *
2113
- * Each row is `[x, y, z, yawDeg?, scale?]` (yaw 0 and scale 1 when omitted) —
2114
- * dense enough to generate hundreds inline. REPLACE the array to update
2115
- * (mutations are not watched).
2116
- */
2117
- declare class InstancedMesh3D extends Node3D {
2118
- static override readonly typeName: string;
2119
- static override readonly props: PropSchema;
2120
- mesh: string;
2121
- size: number[];
2122
- material: MeshMaterialProps;
2123
- castShadow: boolean;
2124
- receiveShadow: boolean;
2125
- /**
2126
- * Make the scatter SOLID: `{}` gives every row a collider shaped like the
2127
- * mesh itself — a faceted `gem` stone collides as that stone's own hull, not
2128
- * as a ball tucked inside it — sized from `size` × the row's scale.
2129
- *
2130
- * A field of fifty boulders a player walks straight through is the tell that
2131
- * a world is a picture. One fixed body carries all the colliders, so the cost
2132
- * is a handful of shapes and no per-frame work — these never move.
2133
- *
2134
- * `{ shape: 'sphere' | 'box' }` (with `radius`/`size`) opts out into a
2135
- * cheaper approximation when a rough blocker is genuinely all you want.
2136
- */
2137
- collider: {
2138
- shape?: string;
2139
- radius?: number;
2140
- size?: number[];
2141
- } | null;
2142
- private _transforms;
2143
- private transformsDirty;
2144
- get transforms(): number[][];
2145
- set transforms(value: number[][]);
2146
- private instanced;
2147
- private builtKey;
2148
- static validateJson(node: Node): void;
2149
- /** Test hook: the live instance count. */
2150
- get instanceCount(): number;
2151
- override _syncObject3D(alpha?: number): void;
2152
- override free(): void;
2153
- }
2154
- //#endregion
2155
2530
  //#region src/3d/nodes/joint-3d.d.ts
2156
- type JointType3D = "fixed" | "spherical" | "rope" | "spring";
2531
+ type JointType3D = "fixed" | "spherical" | "revolute" | "prismatic" | "rope" | "spring";
2157
2532
  /**
2158
2533
  * A physics joint linking its PARENT body to `target` (a node path to the
2159
2534
  * other body). Godot-style placement: the joint lives as a child of body A.
@@ -2162,14 +2537,42 @@ type JointType3D = "fixed" | "spherical" | "rope" | "spring";
2162
2537
  * "props": { "type": "spherical", "target": "%Anchor", "anchor": [0, -20] } }
2163
2538
  *
2164
2539
  * Types: `fixed` welds the bodies rigidly · `spherical` is a ball joint at the
2165
- * anchors · `rope` caps the anchor distance at `length` (m; 0 = measured at
2166
- * creation) · `spring` pulls toward `length` with `stiffness`/`damping`.
2167
- * Anchors are LOCAL meter offsets on each body.
2540
+ * anchors · `revolute` is a HINGE about `axis` (a door, a wheel, a lever) with
2541
+ * optional `limits` (degrees) and a `motorSpeed` (degrees a second) ·
2542
+ * `prismatic` is a SLIDE along `axis` (a portcullis, an elevator, a piston)
2543
+ * with `limits` in metres, a `motorSpeed` in metres a second and `travel`
2544
+ * read back · `rope`
2545
+ * caps the anchor distance at `length` (m; 0 = measured at creation) ·
2546
+ * `spring` pulls toward `length` with `stiffness`/`damping`. Anchors are LOCAL
2547
+ * meter offsets on each body; `angle` reads the hinge back.
2168
2548
  */
2169
2549
  declare class Joint3D extends Node3D {
2170
2550
  static override readonly typeName: string;
2171
2551
  static override readonly props: PropSchema;
2172
2552
  type: JointType3D;
2553
+ /** Hinge axis of a `revolute`, or the line of a `prismatic` (local to this body). */
2554
+ axis: number[];
2555
+ /**
2556
+ * `[min, max]` in degrees for a `revolute` swing; `[]` = no stops. Measured
2557
+ * as `angle` is: this body turned about `axis`, relative to the target.
2558
+ */
2559
+ limits: number[];
2560
+ /** Degrees a second the motor drives the hinge at; `0` = no motor (free). */
2561
+ motorSpeed: number;
2562
+ /** The motor's gain — how quickly it reaches and holds `motorSpeed`. */
2563
+ motorStrength: number;
2564
+ /**
2565
+ * The hinge's current angle in degrees — this body's rotation about `axis`
2566
+ * relative to the target, written by physics every step. `0` when the joint
2567
+ * is not a `revolute` or is not simulated yet.
2568
+ */
2569
+ angle: number;
2570
+ /**
2571
+ * A `prismatic` slide's current travel in metres — this body's anchor along
2572
+ * `axis` relative to the target's, written by physics every step. `0` where
2573
+ * the two anchors coincide, which is where the scene loaded it.
2574
+ */
2575
+ travel: number;
2173
2576
  target: string;
2174
2577
  anchor: number[];
2175
2578
  targetAnchor: number[];
@@ -2558,6 +2961,10 @@ declare class Particles3D extends Node3D {
2558
2961
  maxParticles: number;
2559
2962
  static validateJson(node: Node): void;
2560
2963
  private sim;
2964
+ emitBox: number[];
2965
+ drift: number[];
2966
+ /** @internal Forget the sim so the next update rebuilds it from the props (a preset or kind that changed). */
2967
+ _rebuildSim(): void;
2561
2968
  private bursted;
2562
2969
  private finishedEmitted;
2563
2970
  /** @internal */
@@ -2597,6 +3004,17 @@ declare class Particles3D extends Node3D {
2597
3004
  * list changes (zero per-frame allocation); null when empty so the caller
2598
3005
  * uses the colorStart→colorEnd ramp. */
2599
3006
  private refreshPalette;
3007
+ /**
3008
+ * The stamp every particle is drawn with — a soft round dot.
3009
+ *
3010
+ * A subclass overrides it to look like the thing it IS: `Weather3D`'s rain is
3011
+ * a vertical STREAK, because 2,600 round dots read as a dirty lens and not as
3012
+ * a downpour (measured in a browser at intensity 1). The material is rebuilt
3013
+ * when this changes, so a node may return a different stamp over its life.
3014
+ */
3015
+ protected sprite(): DataTexture;
3016
+ /** The stamp the current material was built with, so a change can rebuild it. */
3017
+ private builtSprite;
2600
3018
  private syncParticles;
2601
3019
  /**
2602
3020
  * Hand the GPU back.
@@ -2609,6 +3027,65 @@ declare class Particles3D extends Node3D {
2609
3027
  override free(): void;
2610
3028
  }
2611
3029
  //#endregion
3030
+ //#region src/3d/nodes/ragdoll-3d.d.ts
3031
+ /** A bone name → world position, metres — what `activate` takes headless. */
3032
+ type RagdollPose = Record<string, [number, number, number]>;
3033
+ /** A built limb: its name in {@link RIG} and the RigidBody3D that is it. */
3034
+ interface Limb {
3035
+ name: string;
3036
+ body: Node;
3037
+ }
3038
+ /**
3039
+ * A ragdoll for a skinned model — the death that falls.
3040
+ *
3041
+ * ```json
3042
+ * { "name": "Body", "type": "CharacterBody3D", "children": [
3043
+ * { "name": "Skin", "type": "ModelInstance3D", "props": { "model": "$base" } },
3044
+ * { "name": "Ragdoll", "type": "Ragdoll3D", "props": { "target": "../Skin", "lifetime": 8 } }
3045
+ * ] }
3046
+ * ```
3047
+ *
3048
+ * Idle it is nothing. `activate()` reads the skeleton at `target` (Mixamo
3049
+ * names, forgiving lookup), builds a capsule `RigidBody3D` per limb where the
3050
+ * bones are, joins each to its parent with a spherical `Joint3D`, gives them
3051
+ * the velocity of the body they fell out of, and from then on writes the
3052
+ * bones' world matrices from the limbs every frame — the model crumples,
3053
+ * slides, hangs off the ledge. Wire it from `Health.died`; turn the body's
3054
+ * collider and its controller off beside it. `reset()` puts the skeleton
3055
+ * back under the animation; `lifetime` does that on its own.
3056
+ *
3057
+ * Headless there is no skeleton: `activate(pose)` takes bone positions, so a
3058
+ * test can ask the same questions the game will.
3059
+ */
3060
+ declare class Ragdoll3D extends Node3D {
3061
+ static override readonly typeName: string;
3062
+ static override readonly props: PropSchema;
3063
+ static override readonly signals: readonly string[];
3064
+ target: string;
3065
+ mass: number;
3066
+ damping: number;
3067
+ lifetime: number;
3068
+ collide: boolean;
3069
+ /** Read-only: built and driving the bones. */
3070
+ active: boolean;
3071
+ private driven;
3072
+ private limbNodes;
3073
+ private left;
3074
+ /** Every limb built right now, empty while idle. */
3075
+ limbs(): Limb[];
3076
+ /**
3077
+ * Build the ragdoll where the skeleton is (or where `pose` says the bones
3078
+ * are, headless). Returns false when there is nothing to build from.
3079
+ */
3080
+ activate(pose?: RagdollPose | undefined): boolean;
3081
+ /** Free the limbs and hand the skeleton back to the animation. */
3082
+ reset(): void;
3083
+ override update(dt: number): void;
3084
+ override free(): void;
3085
+ /** The velocity of the body this ragdoll falls out of — the first body up the tree. */
3086
+ private hostVelocity;
3087
+ }
3088
+ //#endregion
2612
3089
  //#region src/3d/terrain/heightmap.d.ts
2613
3090
  /**
2614
3091
  * A smooth radial depression carved into the terrain — a lake/pond bowl. x/z
@@ -3028,6 +3505,8 @@ declare class River3D extends Node3D implements SunConsumer3D {
3028
3505
  protected override _createObject3D(): Object3D;
3029
3506
  override onReady(): void;
3030
3507
  override onExitTree(): void;
3508
+ /** Said once when the node has no course to be a river along. */
3509
+ private warnedNoPath;
3031
3510
  override update(dt: number): void;
3032
3511
  override _syncObject3D(): void;
3033
3512
  /** Rocks are picked per FRAME (nearest to the eye), scanned on a timer. */
@@ -3263,7 +3742,10 @@ declare class Terrain3D extends Node3D {
3263
3742
  * `heightAt`, the drape and the mesh all pick it up on their next rebuild.
3264
3743
  */
3265
3744
  _setExternalChannel(owner: Node, specs: ChannelSpec[] | null): void;
3266
- /** Authored trenches plus the ones other nodes cut. */
3745
+ /**
3746
+ * Authored trenches plus the ones other nodes cut — every course flattened to
3747
+ * `[x, z]`, whichever spelling it was written in (see `course`).
3748
+ */
3267
3749
  private allChannels;
3268
3750
  /** @internal The pure heightfield (lazily built — physics pulls this). */
3269
3751
  _heightmap(): Heightmap;
@@ -3407,6 +3889,19 @@ declare class Tree3D extends Node3D {
3407
3889
  * it (keeps retrying until a terrain appears), false disables draping.
3408
3890
  */
3409
3891
  drape: boolean | null;
3892
+ /**
3893
+ * Keep trunks out of standing and running water (default true) — a valley a
3894
+ * rill runs through has a grove on its banks, not trees in the current.
3895
+ *
3896
+ * `Foliage3D` and `Flowers3D` have had this since they were written, with the
3897
+ * same default and the same reason; the TREE — the tallest thing in a
3898
+ * landscape and the one that most obviously does not grow midstream — did
3899
+ * not. Measured on a river-valley game: two of twenty-two trunks stood in the
3900
+ * rill.
3901
+ *
3902
+ * `false` is the mangrove, the cypress swamp and the flooded forest.
3903
+ */
3904
+ avoidWater: boolean;
3410
3905
  /** Node path to the Terrain3D to drape onto ('' = auto-find the first one). */
3411
3906
  terrain: string;
3412
3907
  /** Resolved drape target + the grove's world position, set per rebuild. */
@@ -3465,6 +3960,18 @@ declare class Tree3D extends Node3D {
3465
3960
  private buildBarkMaterial;
3466
3961
  private loadBarkTexture;
3467
3962
  /** Per-instance placement + jitter — ONE rng draw order for both paths. */
3963
+ /**
3964
+ * Where every trunk of this grove stands, in WORLD coordinates.
3965
+ *
3966
+ * `drape` is the prop that puts a grove on the ground it grows from, and
3967
+ * nothing could ask whether it had. `UiMinimap.markers()` and
3968
+ * `HudLayer.focusables()` are the same accessor for the same reason: a
3969
+ * feature whose effect no harness can read is a feature nobody checks.
3970
+ *
3971
+ * Recomputed from the seed rather than read back off the InstancedMesh, so it
3972
+ * answers headless too — where there is no mesh at all.
3973
+ */
3974
+ trunks(): Array<[number, number, number]>;
3468
3975
  private scatter;
3469
3976
  private disposeMeshes;
3470
3977
  override free(): void;
@@ -3613,6 +4120,14 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
3613
4120
  * as a calm sea; 0.08 = the noisier ported-source look. */
3614
4121
  waveHeight: number;
3615
4122
  waveSpeed: number;
4123
+ /**
4124
+ * How hard this water holds a floating body back, per second at full
4125
+ * submersion — a pushed crate loses `drag` of its velocity each second (and
4126
+ * its spin likewise), scaled by how much of it is under. `0` is ice; `1.5`
4127
+ * lets a boat coast a few lengths; `6` is syrup. Only bodies with `buoyancy`
4128
+ * feel it (see `RigidBody3D.buoyancy`).
4129
+ */
4130
+ drag: number;
3616
4131
  /** 'fancy' shader water (default) | 'simple' cheap CPU sine material. */
3617
4132
  quality: string;
3618
4133
  /** Fancy ramp overrides: `{trough?, surface?, peak?}` hex strings. */
@@ -3884,6 +4399,22 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
3884
4399
  */
3885
4400
  heightAt(x: number, z: number): number;
3886
4401
  /**
4402
+ * How far below THIS water's surface a world point is, in metres — `0` when
4403
+ * it is above the surface, and `0` when it is outside the pool's footprint.
4404
+ *
4405
+ * `heightAt` answers the surface height everywhere, including a hundred
4406
+ * metres inland, so the obvious spelling of "am I under water"
4407
+ * (`y < water.heightAt(x, z)`) says yes for a player standing in a cellar
4408
+ * well below sea level. The footprint-aware version lived inside
4409
+ * `CharacterController3D`'s swim spring and nothing else could reach it —
4410
+ * and every underwater game needs it for a breath meter, muffled audio, a
4411
+ * "you surfaced" banner, or an enemy that only strikes below.
4412
+ *
4413
+ * The WAVE is included: a point just under a trough is out, and the same
4414
+ * point under a crest is in, which is what a swimmer feels.
4415
+ */
4416
+ depthAt(x: number, y: number, z: number): number;
4417
+ /**
3887
4418
  * @internal Water surface height over a world point, or null outside this
3888
4419
  * surface's footprint — what scattered vegetation asks before it plants a
3889
4420
  * blade (see {@link WetSurface}). The STILL level, not the wave: grass does
@@ -3948,6 +4479,29 @@ declare class WaterCutout3D extends Node3D {
3948
4479
  /** How many cutouts one Water3D reads (the nearest ones win). */
3949
4480
  declare const WATER_CUTOUT_MAX = 4;
3950
4481
  //#endregion
4482
+ //#region src/3d/nodes/weather-3d.d.ts
4483
+ declare class Weather3D extends Particles3D {
4484
+ static override readonly typeName: string;
4485
+ static override readonly props: PropSchema;
4486
+ kind: string;
4487
+ intensity: number;
4488
+ radius: number;
4489
+ height: number;
4490
+ wind: number[];
4491
+ follow: string;
4492
+ /** Rain is a streak; snow keeps the soft flake the particle system draws. */
4493
+ protected override sprite(): DataTexture;
4494
+ private tunedFor;
4495
+ private camera;
4496
+ private cameraScanIn;
4497
+ override onEnterTree(): void;
4498
+ /** Set the inherited particle props from `kind` — once, and again if it changes. */
4499
+ private tune;
4500
+ private tuning;
4501
+ private followed;
4502
+ override update(dt: number): void;
4503
+ }
4504
+ //#endregion
3951
4505
  //#region src/3d/register.d.ts
3952
4506
  /**
3953
4507
  * Register the 3D node taxonomy (and the core nodes). Call once in your game
@@ -4287,9 +4841,31 @@ interface SyncScratch {
4287
4841
  parent: Object3D;
4288
4842
  }>;
4289
4843
  state: WalkState;
4844
+ blend: CameraBlend;
4845
+ }
4846
+ /**
4847
+ * The picture's flight from one camera to the next. `lastPos/Quat/Fov` is the
4848
+ * pose the picture was LAST drawn from — a blend already flying included, so a
4849
+ * second switch mid-blend starts from where the picture is, not from a camera
4850
+ * it never reached.
4851
+ */
4852
+ interface CameraBlend {
4853
+ cam: PerspectiveCamera;
4854
+ active: boolean;
4855
+ t: number;
4856
+ seconds: number;
4857
+ fromPos: Vector3;
4858
+ fromQuat: Quaternion;
4859
+ fromFov: number;
4860
+ lastNode: Camera3D | null;
4861
+ lastPos: Vector3;
4862
+ lastQuat: Quaternion;
4863
+ lastFov: number;
4290
4864
  }
4291
4865
  interface SyncOptions {
4292
4866
  assets?: AssetStore3D;
4867
+ /** Real seconds since the last frame — what a camera blend flies on. */
4868
+ dt?: number;
4293
4869
  /** Sync `static: true` subtrees every frame anyway (the editor's edit mode). */
4294
4870
  ignoreStatic?: boolean;
4295
4871
  /**
@@ -4400,4 +4976,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
4400
4976
  name?: string;
4401
4977
  }): InstancedMesh3D;
4402
4978
  //#endregion
4403
- export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, SpotLight3D, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
4979
+ export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, type Boid, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flock3D, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, type Limb, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, Ragdoll3D, type RagdollPose, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, SpotLight3D, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, Vehicle3D, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, Weather3D, type WheelSpec, type WheelState, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };