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.
- package/bin/incanto-multiplay.mjs +52 -4
- package/dist/2d.d.ts +83 -7
- package/dist/2d.js +4 -3
- package/dist/3d.d.ts +743 -167
- package/dist/3d.js +6 -6
- package/dist/{agent8-CHTT4unP.js → agent8-B-bh3n0X.js} +1 -1
- package/dist/{audio-player-BOrk4eQx.d.ts → audio-player-BRo2uvG6.d.ts} +23 -2
- package/dist/{behavior-J1cmVah0.d.ts → behavior-B_245qRy.d.ts} +15 -1
- package/dist/{create-game-BAiA-FjP.js → create-game-DVUhHs2B.js} +79 -10
- package/dist/{create-game-ssvGvP7W.js → create-game-DnwhJ5nW.js} +83 -7
- package/dist/debug.d.ts +1 -1
- package/dist/{editor-switch-CFU9mCec.d.ts → editor-switch-O8mxpgRX.d.ts} +1 -1
- package/dist/editor.js +1600 -1529
- package/dist/env.d.ts +1 -1
- package/dist/{environment-presets-BkqlWewf.js → environment-presets-BP77Dl0K.js} +2005 -60
- package/dist/{gameplay-Bxe1sMVT.js → gameplay-D-JuGura.js} +9309 -6595
- package/dist/gameplay.d.ts +573 -31
- package/dist/gameplay.js +3 -2
- package/dist/index.d.ts +150 -6
- package/dist/index.js +6 -6
- package/dist/{loader-BAeWMYfF.d.ts → loader-CbkVdXL8.d.ts} +2 -2
- package/dist/net.d.ts +2 -2
- package/dist/net.js +2 -2
- package/dist/{physics-2d-C-SfvjzH.js → physics-2d-x3bCrQf0.js} +250 -31
- package/dist/{physics-3d-rOzeg890.js → physics-3d-Bz2VPQ6D.js} +673 -51
- package/dist/{picking-BMV34Pjl.js → picking-Buita5T9.js} +2 -2
- package/dist/{save-slots-CEUGeLuB.js → pose-ByFB_J3O.js} +217 -11
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/{register-CjociOtt.js → register-B768Qedj.js} +596 -2
- package/dist/{register-DRQyZKGU.js → register-DxAbTO2T.js} +191 -430
- package/dist/{replay-B6BbgGM_.js → replay-DrqQ6dZj.js} +133 -18
- package/dist/{replay-wZK5Ok5c.d.ts → replay-W5nCw_cU.d.ts} +21 -2
- package/dist/{rng-Bb-IutXB.d.ts → rng-BsXZg3D6.d.ts} +7 -0
- package/dist/{split-screen-BxZ5rBe7.js → split-screen-B-dIcQsQ.js} +10 -5
- package/dist/{split-screen-D6sx8z3Z.d.ts → split-screen-CiLJf2-C.d.ts} +3 -3
- package/dist/{sprite-animation-Bz3DHD_4.js → sprite-animation-SQa5gIu2.js} +8 -6
- package/dist/{src-CqtvYtSN.js → src-DLKVc6Hj.js} +1 -1
- package/dist/{test-CEl0y2Sw.js → test-HlVUeCSn.js} +487 -82
- package/dist/test.d.ts +90 -12
- package/dist/test.js +2 -2
- package/dist/vite.js +3 -3
- package/editor/assets/{agent8-BlzturGi.js → agent8-BXlYM9rv.js} +1 -1
- package/editor/assets/{debug-BMUi8usj.js → debug-S42XGP4Y.js} +1 -1
- package/editor/assets/index-DgrgUKno.js +11046 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +1630 -299
- package/skills/incanto-3d-character.md +358 -20
- package/skills/incanto-audio.md +24 -2
- package/skills/incanto-building-2d-games.md +21 -2
- package/skills/incanto-building-3d-games.md +38 -3
- package/skills/incanto-editor.md +17 -6
- package/skills/incanto-environment.md +227 -2
- package/skills/incanto-game-feel.md +60 -1
- package/skills/incanto-gameplay-behaviors.md +668 -20
- package/skills/incanto-hud.md +116 -0
- package/skills/incanto-multiplayer.md +141 -2
- package/skills/incanto-node-reference.md +393 -16
- package/skills/incanto-performance.md +32 -0
- package/skills/incanto-physics-and-input.md +241 -13
- package/skills/incanto-playtesting.md +2 -2
- package/skills/incanto-save-slots.md +61 -2
- package/skills/incanto-scene-json-authoring.md +13 -0
- package/skills/incanto-verifying-your-game.md +86 -3
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +12 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +151 -2
- package/templates-app/molehill-2d/PROJECT/Status.md +7 -0
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/molehill-2d/src/game.scene.json +129 -2
- package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
- package/templates-app/platformer-2d/docs/project-2d-rules.md +3 -2
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/behaviors.ts +40 -26
- package/templates-app/platformer-2d/src/game.scene.json +144 -2
- package/templates-app/platformer-2d/verify.ts +18 -1
- package/templates-app/star-survivor/PROJECT/Status.md +7 -0
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/behaviors.ts +9 -8
- package/templates-app/star-survivor/src/game.scene.json +142 -4
- package/templates-app/star-survivor/verify.ts +13 -0
- package/templates-app/tps-3d/PROJECT/Status.md +6 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +71 -10
- package/templates-app/village-quest-3d/PROJECT/Status.md +7 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/behaviors.ts +8 -16
- package/templates-app/village-quest-3d/src/grove.scene.json +121 -5
- package/templates-app/village-quest-3d/src/village.scene.json +126 -2
- package/templates-app/village-quest-3d/verify.ts +52 -2
- 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-
|
|
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-
|
|
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-
|
|
5
|
-
import { t as EditorSwitchOptions } from "./editor-switch-
|
|
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-
|
|
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 · `
|
|
2166
|
-
*
|
|
2167
|
-
*
|
|
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
|
-
/**
|
|
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 };
|