incanto 0.28.0 → 0.30.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/README.md +44 -0
- package/bin/incanto-editor.mjs +219 -29
- package/dist/2d.d.ts +54 -6
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +353 -16
- package/dist/3d.js +5 -5
- package/dist/{behavior-CPibUfnH.d.ts → behavior-BAc0erXF.d.ts} +21 -0
- package/dist/{create-game-71TJjW1T.js → create-game-5z_QVtLx.js} +59 -16
- package/dist/{create-game-BRgWpNsa.js → create-game-DuBTv2zI.js} +276 -49
- package/dist/debug-draw-BM3DsvtT.js +18 -0
- package/dist/debug.d.ts +51 -6
- package/dist/debug.js +242 -19
- package/dist/editor-switch-B0wB_DSr.d.ts +59 -0
- package/dist/editor.d.ts +49 -0
- package/dist/editor.js +8554 -0
- package/dist/{gameplay-DEG-TP7D.js → gameplay-Cfr6aFZ1.js} +219 -40
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +31 -3
- package/dist/index.js +2 -2
- package/dist/{loader-DILt9PGC.d.ts → loader-B242FF6N.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-RWYkNKx9.d.ts → pathfinding-BwD974Ss.d.ts} +1 -1
- package/dist/{physics-2d-DiVFFlH3.js → physics-2d-3kOQCtgd.js} +88 -3
- package/dist/{physics-3d--y5clE2j.js → physics-3d-CeRH-Ff_.js} +475 -9
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-nObreUQR.js → register-BTg0EM7s.js} +35 -3
- package/dist/{register-6R75AC7-.js → register-DJ0SByQg.js} +5550 -5073
- package/dist/{register-CvpSUU3O.js → register-DWcWq4QG.js} +22 -2
- package/dist/{register-BFFE1Mh1.js → register-MelqEdza.js} +1 -1
- package/dist/teardown-ByzfDPyu.js +240 -0
- package/dist/test.d.ts +35 -3
- package/dist/test.js +104 -10
- package/dist/vite.d.ts +139 -1
- package/dist/vite.js +355 -4
- package/editor/assets/{agent8-CojUfCXN.js → agent8-CAp0i5qn.js} +1 -1
- package/editor/assets/debug-BoEYfbqK.js +2 -0
- package/editor/assets/index-BO6WU8by.js +10696 -0
- package/editor/index.html +3 -157
- package/package.json +3 -2
- package/schemas/scene.schema.json +102 -4
- package/skills/incanto-3d-models.md +38 -0
- package/skills/incanto-assets.md +13 -0
- package/skills/incanto-building-3d-games.md +83 -6
- package/skills/incanto-editor.md +212 -8
- package/skills/incanto-environment.md +65 -1
- package/skills/incanto-node-reference.md +33 -1
- package/skills/incanto-physics-and-input.md +60 -6
- package/skills/incanto-verifying-your-game.md +57 -2
- package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/vite.config.ts +7 -0
- package/templates-app/tps-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/vite.config.ts +7 -0
- package/templates-app/village-quest-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/vite.config.ts +7 -0
- package/dist/debug-draw-CZmOYjL2.js +0 -13
- package/editor/assets/index-D6RQgROR.js +0 -8330
- package/editor/assets/index-D8QvwvOm.css +0 -1
package/dist/3d.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { s as JsonObject } from "./schema-CcoWb32N.js";
|
|
2
|
-
import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-
|
|
3
|
-
import { t as
|
|
1
|
+
import { i as SceneJson, s as JsonObject } from "./schema-CcoWb32N.js";
|
|
2
|
+
import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-BAc0erXF.js";
|
|
3
|
+
import { t as EditorSwitchOptions } from "./editor-switch-B0wB_DSr.js";
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-B242FF6N.js";
|
|
4
5
|
import { t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
|
|
5
|
-
import { n as PathGrid, s as SpatialPose } from "./pathfinding-
|
|
6
|
-
import { AnimationClip, BufferGeometry, Color, DirectionalLight, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Vector3, WebGLRenderer } from "three";
|
|
6
|
+
import { n as PathGrid, s as SpatialPose } from "./pathfinding-BwD974Ss.js";
|
|
7
|
+
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Vector3, WebGLRenderer } from "three";
|
|
7
8
|
import { VRM } from "@pixiv/three-vrm";
|
|
8
9
|
import { Sky } from "three/examples/jsm/objects/Sky.js";
|
|
9
10
|
import * as RapierNs from "@dimforge/rapier3d-compat";
|
|
@@ -124,13 +125,6 @@ interface SunConsumer3D {
|
|
|
124
125
|
/** @internal Called by syncTree when `environment.sky` declares a sun. */
|
|
125
126
|
_applySunDirection(dir: readonly [number, number, number]): void;
|
|
126
127
|
}
|
|
127
|
-
/**
|
|
128
|
-
* Base of every 3D node: a JSON-prop transform backed by a `THREE.Object3D`.
|
|
129
|
-
*
|
|
130
|
-
* Props stay plain JSON (registry/serializer compatible); the renderer layer
|
|
131
|
-
* pushes them onto the backing object once per frame (`_syncObject3D`).
|
|
132
|
-
* Rotation is in DEGREES in JSON — friendlier for agents and humans.
|
|
133
|
-
*/
|
|
134
128
|
declare class Node3D extends Node {
|
|
135
129
|
static override readonly typeName: string;
|
|
136
130
|
static readonly props: PropSchema;
|
|
@@ -154,6 +148,23 @@ declare class Node3D extends Node {
|
|
|
154
148
|
renderOrder: number;
|
|
155
149
|
/** Named draw-order band; `renderOrder` is the fine offset inside it. */
|
|
156
150
|
orderGroup: string;
|
|
151
|
+
/**
|
|
152
|
+
* PUT THIS ON THE GROUND. `true` sets the node's Y from the terrain under it
|
|
153
|
+
* at load; a number does the same and lifts it by that many metres (a post
|
|
154
|
+
* whose origin sits at its middle wants half its height).
|
|
155
|
+
*
|
|
156
|
+
* Computing a Y by hand is the single most repeated mistake in scene
|
|
157
|
+
* authoring, and it is not a careless one: the number is right when it is
|
|
158
|
+
* written and wrong the moment anything reshapes the ground — a river carving
|
|
159
|
+
* its bed, a basin, a different seed, a generator that mirrors the carve
|
|
160
|
+
* slightly differently. Every "floating boulder", "buried player" and
|
|
161
|
+
* "bridge posts in mid-air" in this engine's history is that drift.
|
|
162
|
+
*
|
|
163
|
+
* With this the ground is asked at load, in the same frame the terrain is
|
|
164
|
+
* built, and there is nothing to drift from. `null` (default) leaves `y`
|
|
165
|
+
* exactly as authored — for anything that genuinely hangs in the air.
|
|
166
|
+
*/
|
|
167
|
+
snapToGround: number | boolean | null;
|
|
157
168
|
/** What three actually sorts by: band base + renderOrder. */
|
|
158
169
|
get effectiveRenderOrder(): number;
|
|
159
170
|
private _object3D;
|
|
@@ -165,6 +176,22 @@ declare class Node3D extends Node {
|
|
|
165
176
|
*/
|
|
166
177
|
_interpPrev: number[] | null;
|
|
167
178
|
_interpCurr: number[] | null;
|
|
179
|
+
override onReady(): void;
|
|
180
|
+
/**
|
|
181
|
+
* Resolve {@link snapToGround} against the terrain under this node.
|
|
182
|
+
*
|
|
183
|
+
* Ancestor transforms are translation-only here, the same contract heightAt
|
|
184
|
+
* and the physics heightfield already follow, so the world height converts
|
|
185
|
+
* back to a local Y by subtracting the parents' offset.
|
|
186
|
+
*/
|
|
187
|
+
applyGroundSnap(): void;
|
|
188
|
+
/**
|
|
189
|
+
* @internal The backing object IF it has been built — never builds one.
|
|
190
|
+
*
|
|
191
|
+
* `_ensureObject3D()` is the wrong call during teardown: it allocates a mesh
|
|
192
|
+
* for a node that never rendered, purely so the next line can dispose it.
|
|
193
|
+
*/
|
|
194
|
+
protected get _builtObject3D(): Object3D | null;
|
|
168
195
|
/** @internal The backing three object (lazily created). */
|
|
169
196
|
_ensureObject3D(): Object3D;
|
|
170
197
|
/** @internal Override point for subclasses (mesh, camera, light…). */
|
|
@@ -249,6 +276,20 @@ type Rapier = typeof RapierNs;
|
|
|
249
276
|
interface Physics3DOptions {
|
|
250
277
|
/** m/s², y-up. Default: scene `physics.gravity`, else [0, -9.81, 0]. */
|
|
251
278
|
gravity?: [number, number, number];
|
|
279
|
+
/**
|
|
280
|
+
* Build the colliders and keep them on the tree, but never advance the world
|
|
281
|
+
* (default: `true`, i.e. simulate).
|
|
282
|
+
*
|
|
283
|
+
* This exists for the scene editor. "Show colliders" there used to hand-draw
|
|
284
|
+
* wireframes from the `collider` JSON — which cannot show what the engine
|
|
285
|
+
* actually creates, because the shape is not always in the JSON (a mesh-fitted
|
|
286
|
+
* body, a scatter's hulls, a character capsule) and the drawing ignored
|
|
287
|
+
* rotation and scale. With `simulate: false` the editor gets the SAME lines
|
|
288
|
+
* play mode gets, from the same Rapier world, without anything falling over
|
|
289
|
+
* the moment you look at it: bodies are posed FROM the tree each tick and the
|
|
290
|
+
* solver never runs.
|
|
291
|
+
*/
|
|
292
|
+
simulate?: boolean;
|
|
252
293
|
}
|
|
253
294
|
/**
|
|
254
295
|
* Enable 3D physics for an engine. Dynamically imports Rapier (compat build)
|
|
@@ -259,9 +300,11 @@ declare function enablePhysics3D(engine: Engine, opts?: Physics3DOptions): Promi
|
|
|
259
300
|
/** Per-engine 3D physics world. Same contract as Physics2D. */
|
|
260
301
|
declare class Physics3D {
|
|
261
302
|
private readonly R;
|
|
262
|
-
|
|
303
|
+
readonly engine: Engine;
|
|
263
304
|
/** Render collider outlines in the GAME view (renderers pick this up). */
|
|
264
305
|
debugDraw: boolean;
|
|
306
|
+
/** Narrow those outlines to one node's subtree (see DebugLineSource). */
|
|
307
|
+
debugScope: object | null;
|
|
265
308
|
readonly dimension = "3d";
|
|
266
309
|
private readonly unregisterDebug;
|
|
267
310
|
private readonly warnedNoCollider;
|
|
@@ -275,19 +318,54 @@ declare class Physics3D {
|
|
|
275
318
|
private readonly optsGravity;
|
|
276
319
|
private lastScene;
|
|
277
320
|
constructor(R: Rapier, engine: Engine, opts?: Physics3DOptions);
|
|
321
|
+
/** Whether the solver runs at all. False = collider outlines only. */
|
|
322
|
+
private readonly simulate;
|
|
278
323
|
/** @internal Driven by engine.fixedUpdated. */
|
|
279
324
|
step(dt: number): void;
|
|
325
|
+
/**
|
|
326
|
+
* Move every body to its node's current transform.
|
|
327
|
+
*
|
|
328
|
+
* Only used in outline mode: normally physics owns the pose and writes it
|
|
329
|
+
* INTO the node, so nothing re-reads the tree. Deliberately computed the same
|
|
330
|
+
* way `ensureEntry` computes a body's initial pose — world position, node-local
|
|
331
|
+
* euler — so an outline in the editor is the outline the game will draw, right
|
|
332
|
+
* down to the places where that pair disagrees with a rotated parent.
|
|
333
|
+
*/
|
|
334
|
+
private poseFromTree;
|
|
280
335
|
/** @internal Called by CharacterBody3D.moveAndSlide (during tree fixedUpdate). */
|
|
281
336
|
moveAndSlide(node: CharacterBody3D): void;
|
|
282
337
|
/** Rapier debug segments (meters). Null while debugDraw is off. */
|
|
283
338
|
debugLines(): Float32Array | null;
|
|
339
|
+
/**
|
|
340
|
+
* The Rapier bodies a selected node stands for: its own, its descendants',
|
|
341
|
+
* and — when it owns none — the nearest body ABOVE it, so clicking the visual
|
|
342
|
+
* mesh child of a StaticBody3D shows that body's collider rather than nothing.
|
|
343
|
+
*/
|
|
344
|
+
private scopedBodies;
|
|
284
345
|
dispose(): void;
|
|
285
346
|
private lastStructure;
|
|
286
347
|
private lastRoot;
|
|
287
348
|
private readonly jointSet;
|
|
288
349
|
private readonly joints;
|
|
350
|
+
/** One fixed body per solid scatter field, carrying a collider per row. */
|
|
351
|
+
private readonly scatterBodies;
|
|
289
352
|
private readonly bodySet;
|
|
353
|
+
/**
|
|
354
|
+
* Give every row of a scatter field its own static collider.
|
|
355
|
+
*
|
|
356
|
+
* A stone field is one node with fifty transforms in it, and a player walking
|
|
357
|
+
* through all fifty is what gives a world away as scenery. All of them hang
|
|
358
|
+
* off ONE fixed body — they never move, so there is nothing to step — and the
|
|
359
|
+
* whole set is rebuilt only when the tree's shape changes.
|
|
360
|
+
*/
|
|
361
|
+
private syncScatters;
|
|
290
362
|
private syncBodies;
|
|
363
|
+
/**
|
|
364
|
+
* Null while a `{"shape":"auto"}` body is waiting on its model — the shape
|
|
365
|
+
* lives in the model's triangles, and there is nothing honest to guess in the
|
|
366
|
+
* meantime. syncBodies runs every step, so the body appears the moment the
|
|
367
|
+
* download lands.
|
|
368
|
+
*/
|
|
291
369
|
private ensureEntry;
|
|
292
370
|
/** Apply a world-space impulse to a dynamic body (character controllers). */
|
|
293
371
|
applyImpulse(node: PhysicsBody3D, impulse: [number, number, number]): void;
|
|
@@ -374,6 +452,20 @@ interface CreateGame3DOptions {
|
|
|
374
452
|
_debugDoc?: {
|
|
375
453
|
createElement(tag: string): HTMLElement;
|
|
376
454
|
};
|
|
455
|
+
/**
|
|
456
|
+
* LIVE EDITING: the ☰ debug menu gains "edit this scene", which turns this
|
|
457
|
+
* page into the scene editor — same window, no reload — and the editor's play
|
|
458
|
+
* button turns it back into the game. The scene and the camera survive both
|
|
459
|
+
* crossings.
|
|
460
|
+
*
|
|
461
|
+
* DEFAULTS TO `debug`: a build with the debug overlay is a build someone is
|
|
462
|
+
* working on, and "the scene I am looking at, open in the editor" is what
|
|
463
|
+
* working on it means. It costs nothing until clicked — the editor is a lazy
|
|
464
|
+
* chunk. `false` opts out; `{ open }` loads it yourself (apps that alias
|
|
465
|
+
* incanto to source); `{ save }` makes the editor's save button write your
|
|
466
|
+
* file. Never reachable without `debug` — the ☰ menu is its only entrance.
|
|
467
|
+
*/
|
|
468
|
+
editor?: boolean | EditorSwitchOptions;
|
|
377
469
|
seed?: number;
|
|
378
470
|
fixedHz?: number;
|
|
379
471
|
pixelRatio?: number;
|
|
@@ -381,6 +473,19 @@ interface CreateGame3DOptions {
|
|
|
381
473
|
* (default ON). `false` pins the resolution — screenshots, capture, tests. */
|
|
382
474
|
adaptiveResolution?: boolean;
|
|
383
475
|
resolveScene?: LoadSceneOptions["resolveScene"];
|
|
476
|
+
/**
|
|
477
|
+
* Boot progress, for the loading screen an app already has.
|
|
478
|
+
*
|
|
479
|
+
* Assets are only the FIRST half of a boot: building a dressed scene and
|
|
480
|
+
* compiling its GPU programs takes as long again, and a bar that hits 100%
|
|
481
|
+
* on the last downloaded byte then sits there while the world is built is
|
|
482
|
+
* worse than no bar — the player reads "done" and waits anyway.
|
|
483
|
+
*
|
|
484
|
+
* `fraction` runs 0 → 1 across everything this call does, and `label` names
|
|
485
|
+
* the phase ('scene', 'physics', 'renderer', 'shaders', 'ready'). Feed the
|
|
486
|
+
* asset preload into the first half and this into the second.
|
|
487
|
+
*/
|
|
488
|
+
onProgress?: (fraction: number, label: string) => void;
|
|
384
489
|
/** @internal Test seam — replaces the Renderer3D construction. */
|
|
385
490
|
_rendererFactory?: (engine: Engine, canvas: HTMLCanvasElement) => GameRenderer;
|
|
386
491
|
/** @internal Test seam — replaces the rAF scheduler. */
|
|
@@ -394,10 +499,32 @@ interface GameRenderer {
|
|
|
394
499
|
interface Game3D {
|
|
395
500
|
engine: Engine;
|
|
396
501
|
scene: Scene$1;
|
|
502
|
+
/**
|
|
503
|
+
* The AUTHORED scene this game booted from — the JSON, not the live tree.
|
|
504
|
+
*
|
|
505
|
+
* A running tree has moved: physics has stepped it, behaviors have spawned
|
|
506
|
+
* into it, the player is somewhere else. Handing that to an editor would
|
|
507
|
+
* make "edit the scene" mean "edit wherever the simulation happens to be",
|
|
508
|
+
* so the source is kept beside the game and handed over unchanged.
|
|
509
|
+
*/
|
|
510
|
+
sourceJson: SceneJson;
|
|
397
511
|
renderer: GameRenderer;
|
|
398
512
|
physics: Physics3D | null;
|
|
399
513
|
/** Engine + renderer perf counters in one read (fps/nodes/triangles/…). */
|
|
400
514
|
stats(): GameStats;
|
|
515
|
+
/**
|
|
516
|
+
* Turn this page into the scene editor, right where the player is standing —
|
|
517
|
+
* what the ☰ debug menu's "edit this scene" calls. Bind it to your own key or
|
|
518
|
+
* button if you want the switch without the overlay.
|
|
519
|
+
*
|
|
520
|
+
* Resolves once the editor has taken the page. The game is disposed on the
|
|
521
|
+
* way out and rebooted when the editor hands it back, so the `Game3D` this
|
|
522
|
+
* was called on is DEAD afterwards — take the new one from the editor's
|
|
523
|
+
* `play` path if you need a handle.
|
|
524
|
+
*
|
|
525
|
+
* `null` when the game was booted with `editor: false` — nothing to open.
|
|
526
|
+
*/
|
|
527
|
+
openEditor: (() => Promise<void>) | null;
|
|
401
528
|
dispose(): void;
|
|
402
529
|
}
|
|
403
530
|
/**
|
|
@@ -1269,6 +1396,23 @@ declare class InstancedMesh3D extends Node3D {
|
|
|
1269
1396
|
material: MeshMaterialProps;
|
|
1270
1397
|
castShadow: boolean;
|
|
1271
1398
|
receiveShadow: boolean;
|
|
1399
|
+
/**
|
|
1400
|
+
* Make the scatter SOLID: `{}` gives every row a collider shaped like the
|
|
1401
|
+
* mesh itself — a faceted `gem` stone collides as that stone's own hull, not
|
|
1402
|
+
* as a ball tucked inside it — sized from `size` × the row's scale.
|
|
1403
|
+
*
|
|
1404
|
+
* A field of fifty boulders a player walks straight through is the tell that
|
|
1405
|
+
* a world is a picture. One fixed body carries all the colliders, so the cost
|
|
1406
|
+
* is a handful of shapes and no per-frame work — these never move.
|
|
1407
|
+
*
|
|
1408
|
+
* `{ shape: 'sphere' | 'box' }` (with `radius`/`size`) opts out into a
|
|
1409
|
+
* cheaper approximation when a rough blocker is genuinely all you want.
|
|
1410
|
+
*/
|
|
1411
|
+
collider: {
|
|
1412
|
+
shape?: string;
|
|
1413
|
+
radius?: number;
|
|
1414
|
+
size?: number[];
|
|
1415
|
+
} | null;
|
|
1272
1416
|
private _transforms;
|
|
1273
1417
|
private transformsDirty;
|
|
1274
1418
|
get transforms(): number[][];
|
|
@@ -1423,6 +1567,23 @@ declare class ModelInstance3D extends Node3D {
|
|
|
1423
1567
|
/** false = play the clip once, then emit `animationFinished`. */
|
|
1424
1568
|
animationLoop: boolean;
|
|
1425
1569
|
/**
|
|
1570
|
+
* Playback rate of BOTH animation layers. 1 is the speed the clip was
|
|
1571
|
+
* authored at; 0.5 halves it, 2 doubles it, 0 freezes on the current pose.
|
|
1572
|
+
* Negative plays backwards (a closing door is an opening one reversed).
|
|
1573
|
+
*
|
|
1574
|
+
* Live: changing it retimes the clip already playing, no restart.
|
|
1575
|
+
*/
|
|
1576
|
+
animationSpeed: number;
|
|
1577
|
+
/**
|
|
1578
|
+
* Seconds into the clip to start at.
|
|
1579
|
+
*
|
|
1580
|
+
* A row of identical torches all starting at 0 flickers in lockstep and the
|
|
1581
|
+
* eye reads it instantly as "copies". Give each a different offset and the
|
|
1582
|
+
* same clip becomes a crowd. Applied when a clip STARTS (a restart re-seeks),
|
|
1583
|
+
* wrapped into the clip's duration, so any number is legal.
|
|
1584
|
+
*/
|
|
1585
|
+
animationOffset: number;
|
|
1586
|
+
/**
|
|
1426
1587
|
* Two-layer animation: play this clip on the UPPER BODY ONLY (the
|
|
1427
1588
|
* `upperBodyRoot` bone subtree) while `animation` keeps driving the rest —
|
|
1428
1589
|
* attack while running, wave while walking. One-shot by default
|
|
@@ -1447,7 +1608,21 @@ declare class ModelInstance3D extends Node3D {
|
|
|
1447
1608
|
private mountedRef;
|
|
1448
1609
|
private fittedHeight;
|
|
1449
1610
|
private fitGroup;
|
|
1611
|
+
/**
|
|
1612
|
+
* @internal The mounted model, or null while the asset is still loading.
|
|
1613
|
+
* Physics reads this to shape a `{"shape":"auto"}` collider on the real
|
|
1614
|
+
* triangles — nothing else may reach into the loaded three graph.
|
|
1615
|
+
*/
|
|
1616
|
+
_mountedObject3D(): Group | null;
|
|
1450
1617
|
private mixer;
|
|
1618
|
+
/** The offset the playing clip was seeked to — re-seek when the prop moves. */
|
|
1619
|
+
private appliedOffset;
|
|
1620
|
+
/** @internal Test seam — the mixer driving this model's clips. */
|
|
1621
|
+
get _mixer(): AnimationMixer | null;
|
|
1622
|
+
/** @internal Test seam — which `animation` key is actually playing. */
|
|
1623
|
+
get _playingClip(): string;
|
|
1624
|
+
/** @internal Test seam — where the base clip currently is, in seconds. */
|
|
1625
|
+
get _currentActionTime(): number;
|
|
1451
1626
|
private playing;
|
|
1452
1627
|
private currentAction;
|
|
1453
1628
|
private playingUpper;
|
|
@@ -1733,6 +1908,30 @@ interface PathSample {
|
|
|
1733
1908
|
/** Meters from the source. */
|
|
1734
1909
|
along: number;
|
|
1735
1910
|
}
|
|
1911
|
+
/** One reach where the ribbon could not cover the ground its water stands on. */
|
|
1912
|
+
interface RiverCoverageGap {
|
|
1913
|
+
/** Metres from the source. */
|
|
1914
|
+
along: number;
|
|
1915
|
+
/** What the terrain says is under water at this station. */
|
|
1916
|
+
wettedHalfWidth: number;
|
|
1917
|
+
/** What a ribbon can carry through the bend here. */
|
|
1918
|
+
carriedHalfWidth: number;
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Where a river's ribbon falls short of the water it is standing in.
|
|
1922
|
+
*
|
|
1923
|
+
* A swept ribbon has a hard geometric ceiling — it cannot be wider than the
|
|
1924
|
+
* bend it is taking, or its inner edge folds through itself. When the ground
|
|
1925
|
+
* under the surface is wetter than that ceiling allows, the ribbon leaves BARE
|
|
1926
|
+
* CHANNEL FLOOR beside the water, and to a player the creek simply stops in
|
|
1927
|
+
* the middle of its own bed. No amount of shader work fixes it: the surface
|
|
1928
|
+
* really is missing.
|
|
1929
|
+
*
|
|
1930
|
+
* This reports those reaches so a caller can act on them instead of shipping
|
|
1931
|
+
* them. River3D calls it at build time and warns; `incanto/test` exposes it so
|
|
1932
|
+
* a game can gate on it headlessly.
|
|
1933
|
+
*/
|
|
1934
|
+
declare function findRiverCoverageGaps(rings: readonly RiverRing[], tolerance?: number): RiverCoverageGap[];
|
|
1736
1935
|
/** A cross-section station: where the water is, how wide, how fast. */
|
|
1737
1936
|
interface RiverRing extends PathSample {
|
|
1738
1937
|
/** The width the author ASKED for (half of it) — nominal, drives current. */
|
|
@@ -1740,6 +1939,9 @@ interface RiverRing extends PathSample {
|
|
|
1740
1939
|
/** Wetted half-width to the left of the flow: where the ground rises to the
|
|
1741
1940
|
* surface. This, not {@link halfWidth}, is where the water actually ends. */
|
|
1742
1941
|
halfLeft: number;
|
|
1942
|
+
/** What the terrain scan asked for before the bend capped it (fit only). */
|
|
1943
|
+
wettedLeft?: number;
|
|
1944
|
+
wettedRight?: number;
|
|
1743
1945
|
/** Wetted half-width to the right of the flow. */
|
|
1744
1946
|
halfRight: number;
|
|
1745
1947
|
/** No bank on that side: the ground never came up to the surface, so the
|
|
@@ -1754,6 +1956,26 @@ interface RiverRing extends PathSample {
|
|
|
1754
1956
|
/** Surface current in m/s. */
|
|
1755
1957
|
speed: number;
|
|
1756
1958
|
}
|
|
1959
|
+
interface RiverRingOptions {
|
|
1960
|
+
path: readonly (readonly number[])[];
|
|
1961
|
+
/** One entry = constant width; several = a profile lerped source→mouth. */
|
|
1962
|
+
widths: readonly number[];
|
|
1963
|
+
/** Water column at the centerline, in meters. */
|
|
1964
|
+
depth: number;
|
|
1965
|
+
/** Reference current in m/s (the mean over the river). */
|
|
1966
|
+
flowSpeed: number;
|
|
1967
|
+
/** Centerline sampling step in meters. */
|
|
1968
|
+
step: number;
|
|
1969
|
+
bedAt: BedSampler;
|
|
1970
|
+
/**
|
|
1971
|
+
* Fit the surface to the ground across the channel — the surface may not
|
|
1972
|
+
* stand above the rim that holds it, and the ribbon ends where the ground
|
|
1973
|
+
* comes up to meet it. Default OFF, because it is meaningful only when
|
|
1974
|
+
* `bedAt` is REAL ground: a river with no terrain under it invents a bed one
|
|
1975
|
+
* `depth` below itself, and there is nothing there to contain or spill it.
|
|
1976
|
+
*/
|
|
1977
|
+
fit?: boolean;
|
|
1978
|
+
}
|
|
1757
1979
|
interface RiverHit {
|
|
1758
1980
|
/** In the channel: inside the banks AND between source and mouth. */
|
|
1759
1981
|
inside: boolean;
|
|
@@ -1768,11 +1990,57 @@ interface RiverHit {
|
|
|
1768
1990
|
speed: number;
|
|
1769
1991
|
halfWidth: number;
|
|
1770
1992
|
}
|
|
1993
|
+
/**
|
|
1994
|
+
* Make a traced course fit to carry a river of a given width.
|
|
1995
|
+
*
|
|
1996
|
+
* `traceDownhillPath` follows the steepest descent, which on real terrain
|
|
1997
|
+
* zigzags, kinks and sometimes hooks back within a few metres of a reach it
|
|
1998
|
+
* already ran. A ribbon on such a course cannot be well formed at any width
|
|
1999
|
+
* worth looking at: tight corners fold its inner edge, and a hook stacks two
|
|
2000
|
+
* sheets of water on the same ground. Every symptom of that is a rendering
|
|
2001
|
+
* artifact with no rendering fix.
|
|
2002
|
+
*
|
|
2003
|
+
* So the course is conditioned first, in three steps that are all about the
|
|
2004
|
+
* WIDTH the river will be:
|
|
2005
|
+
* 1. Laplacian passes relax the trace toward a curve whose bends a ribbon of
|
|
2006
|
+
* `halfWidth` can take.
|
|
2007
|
+
* 2. Points closer together than the width are dropped — they only encode
|
|
2008
|
+
* noise at that scale.
|
|
2009
|
+
* 3. The course is CUT where it comes back within two widths of itself: a
|
|
2010
|
+
* creek does not flow over its own reach, and ending is a better answer
|
|
2011
|
+
* than two stacked sheets or a strangled trickle.
|
|
2012
|
+
*
|
|
2013
|
+
* Use it on anything `traceDownhillPath` produces before handing it to River3D.
|
|
2014
|
+
*/
|
|
2015
|
+
declare function smoothCourse(path: readonly (readonly number[])[], halfWidth: number, passes?: number): number[][];
|
|
2016
|
+
/**
|
|
2017
|
+
* The centerline station spacing River3D itself uses — EXPORTED so a generator
|
|
2018
|
+
* placing things against the water calls the same derivation. A hardcoded step
|
|
2019
|
+
* puts the generator's stations in different places than the node's; on a
|
|
2020
|
+
* smooth reach nobody notices, on a tight tail the two snap to different rings
|
|
2021
|
+
* and rocks grown for one water stand beside the other.
|
|
2022
|
+
*/
|
|
2023
|
+
declare function riverStepFor(widths: readonly number[], depth: number): number;
|
|
2024
|
+
declare function buildRiverRings(opts: RiverRingOptions): RiverRing[];
|
|
2025
|
+
declare function projectToRiver(rings: readonly RiverRing[], x: number, z: number): RiverHit | null;
|
|
1771
2026
|
/** A place where the river stops flowing and starts falling. */
|
|
1772
2027
|
interface RiverFall {
|
|
1773
2028
|
/** Where the water LANDS (local frame) — the plunge point. */
|
|
1774
2029
|
x: number;
|
|
1775
2030
|
z: number;
|
|
2031
|
+
/** Where it LEAVES: the lip. A falling sheet hangs from here, not from the
|
|
2032
|
+
* plunge — hanging it downstream is how a curtain ends up floating in the
|
|
2033
|
+
* air past the cliff it should be pouring over. */
|
|
2034
|
+
lipX: number;
|
|
2035
|
+
lipZ: number;
|
|
2036
|
+
/** Water half-width AT THE LIP — a fall is as wide as the water going over
|
|
2037
|
+
* the edge, not as wide as the pool it lands in. */
|
|
2038
|
+
lipHalfWidth: number;
|
|
2039
|
+
/** Downstream direction at the lip. */
|
|
2040
|
+
lipDirX: number;
|
|
2041
|
+
lipDirZ: number;
|
|
2042
|
+
/** Current at the lip — what throws the sheet forward. */
|
|
2043
|
+
lipSpeed: number;
|
|
1776
2044
|
/** Water surface at the lip and at the base. */
|
|
1777
2045
|
topY: number;
|
|
1778
2046
|
baseY: number;
|
|
@@ -1891,6 +2159,8 @@ declare class River3D extends Node3D implements SunConsumer3D {
|
|
|
1891
2159
|
private bedAt;
|
|
1892
2160
|
/** Whether the last course was fitted to real ground (see buildRiverRings). */
|
|
1893
2161
|
private fitted;
|
|
2162
|
+
private bounds;
|
|
2163
|
+
private boundsKey;
|
|
1894
2164
|
/** Everything standing in the current, rescanned on a slow timer. */
|
|
1895
2165
|
private rocks;
|
|
1896
2166
|
private rockScanAt;
|
|
@@ -1911,6 +2181,9 @@ declare class River3D extends Node3D implements SunConsumer3D {
|
|
|
1911
2181
|
* plants a blade (see {@link WetSurface}).
|
|
1912
2182
|
*/
|
|
1913
2183
|
_waterYAt(x: number, z: number): number | null;
|
|
2184
|
+
/** XZ bounds of the wetted channel, padded by its widest reach. Rebuilt with
|
|
2185
|
+
* the course (the key is the same one the course is derived under). */
|
|
2186
|
+
private ringBounds;
|
|
1914
2187
|
/**
|
|
1915
2188
|
* Where a WORLD point sits in the channel — the query gameplay scripts run
|
|
1916
2189
|
* (steer a raft, drown a torch, decide a ford is too fast to cross). `null`
|
|
@@ -1953,6 +2226,18 @@ declare class River3D extends Node3D implements SunConsumer3D {
|
|
|
1953
2226
|
* Pure CPU work — no three objects — so gameplay can call it any time.
|
|
1954
2227
|
*/
|
|
1955
2228
|
private ensureCourse;
|
|
2229
|
+
/**
|
|
2230
|
+
* Say so when the course cannot carry the water standing in it.
|
|
2231
|
+
*
|
|
2232
|
+
* A swept ribbon may not be wider than the bend it takes (its inner edge
|
|
2233
|
+
* would fold through itself), so where the ground is wetter than that ceiling
|
|
2234
|
+
* the surface leaves BARE CHANNEL FLOOR — the creek visibly stops in the
|
|
2235
|
+
* middle of its own bed. That is a course/width mismatch the author has to
|
|
2236
|
+
* decide about, and it is invisible from the JSON, so it is said out loud
|
|
2237
|
+
* with the three things that fix it.
|
|
2238
|
+
*/
|
|
2239
|
+
private warnUncoveredWater;
|
|
2240
|
+
private warnedCoverage;
|
|
1956
2241
|
private rebuildIfNeeded;
|
|
1957
2242
|
private buildMaterial;
|
|
1958
2243
|
/**
|
|
@@ -2062,6 +2347,10 @@ declare class Terrain3D extends Node3D {
|
|
|
2062
2347
|
* dug", and re-loading the scene digs it again.
|
|
2063
2348
|
*/
|
|
2064
2349
|
private readonly externalChannels;
|
|
2350
|
+
/** Bumped whenever an external channel is cut or released. */
|
|
2351
|
+
private externalRev;
|
|
2352
|
+
/** What the cached heightmap was built from (see shapeUnchanged). */
|
|
2353
|
+
private shapeStamp;
|
|
2065
2354
|
/**
|
|
2066
2355
|
* WET SAND band: `{ y, band? }` darkens + glosses the splat in a noisy,
|
|
2067
2356
|
* breathing band just above height `y` (a waterline) — the trace of the
|
|
@@ -2097,6 +2386,9 @@ declare class Terrain3D extends Node3D {
|
|
|
2097
2386
|
private allChannels;
|
|
2098
2387
|
/** @internal The pure heightfield (lazily built — physics pulls this). */
|
|
2099
2388
|
_heightmap(): Heightmap;
|
|
2389
|
+
/** Cheap guard for the heightmap cache: scalars by value, arrays by identity. */
|
|
2390
|
+
private shapeUnchanged;
|
|
2391
|
+
private rememberShape;
|
|
2100
2392
|
/** The splat layers in effect — theme preset, or `layers` for 'custom'. */
|
|
2101
2393
|
resolvedLayers(): TerrainLayer[];
|
|
2102
2394
|
override _syncObject3D(): void;
|
|
@@ -2404,6 +2696,16 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
|
|
|
2404
2696
|
reflectionInterval: number;
|
|
2405
2697
|
/** Depth-texture shoreline foam — rides the always-on fancy scene pass. */
|
|
2406
2698
|
foam: boolean;
|
|
2699
|
+
/**
|
|
2700
|
+
* How much sky the surface throws back at grazing angles, 0..1 — `null`
|
|
2701
|
+
* keeps the preset's own ceiling.
|
|
2702
|
+
*
|
|
2703
|
+
* Turn it DOWN when the sky is blown out: a bright overcast reflected at 0.78
|
|
2704
|
+
* is a sheet of white, and a pool doing that next to a River3D (which paints
|
|
2705
|
+
* an AUTHORED sky palette and so never blows out) reads as two unrelated
|
|
2706
|
+
* materials meeting at a line. Turn it up for a mirror-calm lake.
|
|
2707
|
+
*/
|
|
2708
|
+
reflectivity: number | null;
|
|
2407
2709
|
/** Bodies crossing the surface emit signals and raise ripples. */
|
|
2408
2710
|
interaction: boolean;
|
|
2409
2711
|
/** Splash WHITEWATER: the shaders paint expanding surface foam where bodies
|
|
@@ -2510,6 +2812,9 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
|
|
|
2510
2812
|
private readonly mirrorCamera;
|
|
2511
2813
|
private readonly mirrorMatrix;
|
|
2512
2814
|
private lastMirrorAt;
|
|
2815
|
+
/** Camera pose the current mirror image was rendered from (see redraw). */
|
|
2816
|
+
private readonly lastMirrorEye;
|
|
2817
|
+
private readonly lastMirrorQuat;
|
|
2513
2818
|
protected override _createObject3D(): Object3D;
|
|
2514
2819
|
override update(dt: number): void;
|
|
2515
2820
|
override _syncObject3D(): void;
|
|
@@ -2691,6 +2996,11 @@ declare class Renderer3D {
|
|
|
2691
2996
|
private readonly loadedAssetScenes;
|
|
2692
2997
|
/** The scene whose GPU programs have been pre-compiled (warm-up, see render). */
|
|
2693
2998
|
private compiledScene;
|
|
2999
|
+
/** The camera the last frame drew with — what warmUp compiles against. */
|
|
3000
|
+
private warmCamera;
|
|
3001
|
+
/** Set while a caller intends to run {@link warmUp} instead: the first frame
|
|
3002
|
+
* then compiles only what it actually draws, and the rest goes async. */
|
|
3003
|
+
private deferCompile;
|
|
2694
3004
|
/** Reused per-frame walk scratch (instance-scoped — never a module global). */
|
|
2695
3005
|
private readonly syncScratch;
|
|
2696
3006
|
/** Editors set this: keep syncing `static: true` subtrees every frame. */
|
|
@@ -2740,6 +3050,20 @@ declare class Renderer3D {
|
|
|
2740
3050
|
* grab, the mirror and the bloom chain follow automatically.
|
|
2741
3051
|
*/
|
|
2742
3052
|
private governResolution;
|
|
3053
|
+
/**
|
|
3054
|
+
* Compile the scene's GPU programs off the critical path.
|
|
3055
|
+
*
|
|
3056
|
+
* The compile itself is unavoidable — a dressed outdoor scene is 40+ programs
|
|
3057
|
+
* and a driver takes hundreds of milliseconds each (measured: SEVEN SECONDS
|
|
3058
|
+
* for this engine's creek template on macOS/Metal). What is avoidable is
|
|
3059
|
+
* doing it in ONE synchronous block, which freezes the tab and leaves a
|
|
3060
|
+
* loading bar with nothing to say.
|
|
3061
|
+
*
|
|
3062
|
+
* Called by `createGame3D` behind the app's loading screen.
|
|
3063
|
+
*/
|
|
3064
|
+
/** @internal Tell the next frame to leave the bulk compile to {@link warmUp}. */
|
|
3065
|
+
deferFirstCompile(): void;
|
|
3066
|
+
warmUp(onProgress?: (fraction: number) => void): Promise<void>;
|
|
2743
3067
|
private render;
|
|
2744
3068
|
/**
|
|
2745
3069
|
* Bloom post pass (only when `environment.bloom` is declared). LDR and safe:
|
|
@@ -2785,10 +3109,23 @@ declare class Renderer3D {
|
|
|
2785
3109
|
*/
|
|
2786
3110
|
pick(sx: number, sy: number): Node | null;
|
|
2787
3111
|
/**
|
|
2788
|
-
* GPU counters for the
|
|
2789
|
-
*
|
|
3112
|
+
* GPU counters for the last rendered frame — EVERY pass of it, summed (see
|
|
3113
|
+
* the `info.reset()` in `render`), plus GPU memory.
|
|
2790
3114
|
*/
|
|
2791
3115
|
stats(): RendererStats;
|
|
3116
|
+
/**
|
|
3117
|
+
* Where the last rendered frame was seen FROM.
|
|
3118
|
+
*
|
|
3119
|
+
* Paired with {@link cameraBasis} this is the view on screen — a third-person
|
|
3120
|
+
* rig, a cutscene camera and the editor's free-fly all answer here, which is
|
|
3121
|
+
* what a mode switch needs to carry across so the cut does not read as a
|
|
3122
|
+
* page load.
|
|
3123
|
+
*/
|
|
3124
|
+
lastCameraPosition(): {
|
|
3125
|
+
x: number;
|
|
3126
|
+
y: number;
|
|
3127
|
+
z: number;
|
|
3128
|
+
} | null;
|
|
2792
3129
|
/** The last rendered camera's world-space basis (for screen-plane dragging). */
|
|
2793
3130
|
cameraBasis(): {
|
|
2794
3131
|
right: Vector3;
|
|
@@ -2941,4 +3278,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
|
|
|
2941
3278
|
name?: string;
|
|
2942
3279
|
}): InstancedMesh3D;
|
|
2943
3280
|
//#endregion
|
|
2944
|
-
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 Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverHit, type RiverRing, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
3281
|
+
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 Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-
|
|
3
|
-
import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-
|
|
4
|
-
import { A as
|
|
2
|
+
import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-Cfr6aFZ1.js";
|
|
3
|
+
import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-DuBTv2zI.js";
|
|
4
|
+
import { A as DEFAULT_TERRAIN_TEXTURE_BASE, B as movementState, C as FLOWER_VARIETIES, D as BoneAttachment3D, E as BoneLookAt3D, F as MeshInstance3D, L as QUARTER_PITCH, M as terrainThemeLayers, N as Joint3D, O as Billboard3D, P as InstancedMesh3D, R as cameraRelative, S as resolveFlowerDensity, T as Camera3D, V as rigPose, _ as DirectionalLight3D, a as Trail3D, b as DENSITY_PRESETS, c as findRiverCoverageGaps, d as riverStepFor, f as smoothCourse, g as LoftMesh3D, h as ModelInstance3D, i as Tree3D, j as TERRAIN_THEMES, k as Terrain3D, l as projectToRiver, m as Particles3D, n as VOXEL_PALETTE, o as River3D, p as traceDownhillPath, r as VoxelGrid3D, s as buildRiverRings, t as registerNodes3D, u as riverCarveChannels, v as OmniLight3D, w as CharacterController3D, x as Flowers3D, y as Foliage3D, z as keyboardIntensity } from "./register-DJ0SByQg.js";
|
|
5
5
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
6
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d
|
|
6
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CeRH-Ff_.js";
|
|
7
7
|
//#region src/3d/environment-runtime.ts
|
|
8
8
|
/**
|
|
9
9
|
* Live environment editing — the renderer re-applies `scene.environment`
|
|
@@ -142,4 +142,4 @@ function createNavDebugNode(nav, opts) {
|
|
|
142
142
|
return node;
|
|
143
143
|
}
|
|
144
144
|
//#endregion
|
|
145
|
-
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
145
|
+
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
@@ -791,6 +791,16 @@ declare class Engine {
|
|
|
791
791
|
* `engine.music.play(src)` / `crossfadeTo(src, secs)` / `stop(fadeOut)`;
|
|
792
792
|
* routes through the music bus and is advanced each frame by the loop. */
|
|
793
793
|
readonly music: MusicManager;
|
|
794
|
+
/**
|
|
795
|
+
* Where nodes that build DOM (HudLayer and its widgets) mount their elements.
|
|
796
|
+
*
|
|
797
|
+
* `null` — the default — means `document.body` with `position: fixed`, i.e. a
|
|
798
|
+
* game's HUD covers the window, which is what a game wants. A host that only
|
|
799
|
+
* OWNS PART of the page sets this to its own (positioned) container so the
|
|
800
|
+
* HUD stays inside it: the scene editor points it at the viewport pane, which
|
|
801
|
+
* is why an edited scene's HUD no longer floats over the inspector.
|
|
802
|
+
*/
|
|
803
|
+
uiHost: HTMLElement | null;
|
|
794
804
|
private readonly fixedStep;
|
|
795
805
|
private readonly maxFixedSteps;
|
|
796
806
|
private readonly scheduler;
|
|
@@ -870,6 +880,17 @@ interface PropDef {
|
|
|
870
880
|
/** For enum-like string props: the valid values. Drives editor/debug
|
|
871
881
|
* dropdowns and the generated JSON-Schema enum — keep it exhaustive. */
|
|
872
882
|
options?: readonly string[];
|
|
883
|
+
/**
|
|
884
|
+
* For an OBJECT-valued prop shaped as a tagged union — `collider`, whose
|
|
885
|
+
* `shape` decides which other keys are required. One declaration gives an
|
|
886
|
+
* inspector both the dropdown AND something valid to write when the tag
|
|
887
|
+
* changes: switching `box` → `sphere` must not leave a `size` and no
|
|
888
|
+
* `radius`, which is a hard load error.
|
|
889
|
+
*/
|
|
890
|
+
variants?: {
|
|
891
|
+
/** The key that picks the variant (e.g. `'shape'`). */tag: string; /** Tag value → a COMPLETE, valid value for the prop. */
|
|
892
|
+
byTag: Record<string, JsonValue>;
|
|
893
|
+
};
|
|
873
894
|
}
|
|
874
895
|
type PropSchema = Record<string, PropDef>;
|
|
875
896
|
interface NodeCtor {
|