incanto 0.59.0 → 0.61.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-check.mjs +58 -4
- package/dist/2d.d.ts +22 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +5 -5
- package/dist/3d.js +5 -4
- package/dist/{pathfinding-BqWBb0kh.d.ts → audio-player-D5GJgb_x.d.ts} +103 -38
- package/dist/{behavior-DWKTUzKI.d.ts → behavior-DsgayMsH.d.ts} +79 -1
- package/dist/{create-game-CHDLDQsQ.js → create-game-DH7JI5xx.js} +76 -11
- package/dist/{create-game-BiW8Men_.js → create-game-IX5lEH0P.js} +21 -294
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/{duplicate-DJQd44CD.js → duplicate-CGqAmK2h.js} +1 -1
- package/dist/editor.js +2 -1
- package/dist/{environment-presets-DRAz5EV9.js → environment-presets-CNxCuhZF.js} +48 -13
- package/dist/{gameplay-BBEjPFsR.js → gameplay-Dtzd2itW.js} +53 -11
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +23 -6
- package/dist/index.js +7 -7
- package/dist/{loader-D8n7TU8W.js → loader-D7jTvDQv.js} +797 -2
- package/dist/{loader-TvkRFbyL.d.ts → loader-DolLJWJn.d.ts} +13 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/pathfinding-_fGrCFmH.d.ts +28 -0
- package/dist/{physics-2d-BaRSRrrZ.js → physics-2d-CBnor8Zf.js} +2 -2
- package/dist/{physics-3d-CYxjh-HW.js → physics-3d-BTUfUSWO.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-BpFcgdcL.js → register-DL3izw8j.js} +46 -9
- package/dist/{register-CDrAQqPp.js → register-xuSRyD6b.js} +119 -21
- package/dist/{registry-WWcQcfMr.js → registry-CF70EArN.js} +55 -3
- package/dist/{replay-O-yAGM76.d.ts → replay-C5x2vPF5.d.ts} +16 -3
- package/dist/{replay-CEPyQtF_.js → replay-D7-yle3s.js} +56 -205
- package/dist/{split-screen-DDMZutQ6.js → split-screen-5Ban4q4n.js} +3 -3
- package/dist/{split-screen-BQ3tAsf-.d.ts → split-screen-D7OopelJ.d.ts} +2 -2
- package/dist/{src-CY21B462.js → src-DozXvyZS.js} +1 -1
- package/dist/{teardown-RApWnM1G.js → teardown-B6rwJOyS.js} +1 -1
- package/dist/{test-DHYuFyAu.js → test-Dch_7VQD.js} +19 -14
- package/dist/test.d.ts +24 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-BoRGtVxK.js → agent8-CF1JL2tR.js} +1 -1
- package/editor/assets/{debug-CzdyCg75.js → debug-3QzYhOPA.js} +1 -1
- package/editor/assets/{index-VesuVEhe.js → index-CAD2c5ug.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +4 -0
- package/skills/incanto-3d-models.md +1 -1
- package/skills/incanto-assets.md +10 -1
- package/skills/incanto-audio.md +21 -13
- package/skills/incanto-behaviors-and-scripts.md +7 -3
- package/skills/incanto-building-2d-games.md +12 -3
- package/skills/incanto-editor.md +1 -1
- package/skills/incanto-gameplay-behaviors.md +24 -1
- package/skills/incanto-hud.md +5 -3
- package/skills/incanto-localization.md +31 -0
- package/skills/incanto-node-reference.md +1 -0
- package/skills/incanto-scene-json-authoring.md +6 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/dist/particle-sim-C5OfBbmU.d.ts +0 -77
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Scene, b as Engine } from "./behavior-
|
|
1
|
+
import { P as Scene, b as Engine } from "./behavior-DsgayMsH.js";
|
|
2
2
|
import { i as SceneJson } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/core/scene/loader.d.ts
|
|
@@ -6,6 +6,18 @@ interface LoadSceneOptions {
|
|
|
6
6
|
/** Resolve a sub-scene path referenced by `{instance: '<path>'}`. */
|
|
7
7
|
resolveScene?: (path: string) => SceneJson;
|
|
8
8
|
/**
|
|
9
|
+
* Assets declared ELSEWHERE in the project, for `$ref` validation.
|
|
10
|
+
*
|
|
11
|
+
* A scene a `NetworkSpawner` spawns resolves its refs against the HOST's
|
|
12
|
+
* `assets{}` — `remote-player.scene.json` names `$characters/base` and
|
|
13
|
+
* declares nothing itself, which is correct and cannot be checked from that
|
|
14
|
+
* one file. A tool with the whole project passes the union in; loading the
|
|
15
|
+
* file alone still fails, because alone it really cannot resolve.
|
|
16
|
+
*/
|
|
17
|
+
declaredAssets?: Record<string, {
|
|
18
|
+
type?: unknown;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
9
21
|
* Tool/preview mode (the editor's ▶ play strips behaviors — and their
|
|
10
22
|
* `static signals` with them): declare each connection's signal on its
|
|
11
23
|
* from-node instead of hard-failing with UNKNOWN_SIGNAL. Games should
|
package/dist/net.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-
|
|
1
|
+
import { d as PropSchema, jt as Node } from "./behavior-DsgayMsH.js";
|
|
2
|
+
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-D7OopelJ.js";
|
|
3
3
|
|
|
4
4
|
//#region src/net/agent8.d.ts
|
|
5
5
|
/**
|
package/dist/net.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
|
|
2
|
-
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-
|
|
2
|
+
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-5Ban4q4n.js";
|
|
3
3
|
export { LocalGameServer, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, NetworkSpawner, applySyncPatch, createAgent8Server, createLocalGameServer, createSplitScreen, registerNodesNet };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/core/pathfinding.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Grid A* — the pathfinding every top-down/RPG/tower-defense asks for and
|
|
4
|
+
* agents keep re-inventing badly. Pure and dimension-free: cells in, cells
|
|
5
|
+
* out; the caller maps cells to world units (px, meters, tiles).
|
|
6
|
+
*/
|
|
7
|
+
interface PathGrid {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
/** True = impassable. Out-of-bounds is always solid. */
|
|
11
|
+
solid(x: number, y: number): boolean;
|
|
12
|
+
}
|
|
13
|
+
interface FindPathOptions {
|
|
14
|
+
/** Allow diagonal steps (blocked from cutting corners). Default true. */
|
|
15
|
+
diagonal?: boolean;
|
|
16
|
+
/** Abort guard for huge/impossible searches. Default 20000 nodes. */
|
|
17
|
+
maxExpansions?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A* from `from` to `to` (inclusive cell coords). Returns the cell path
|
|
21
|
+
* INCLUDING both endpoints, or null when unreachable. Straight steps cost
|
|
22
|
+
* 1, diagonals √2; the heuristic is octile (admissible for both modes).
|
|
23
|
+
*/
|
|
24
|
+
declare function findPath(grid: PathGrid, from: [number, number], to: [number, number], opts?: FindPathOptions): [number, number][] | null;
|
|
25
|
+
/** Build a PathGrid from row-strings ('#' = solid) — tests and tile games. */
|
|
26
|
+
declare function gridFromRows(rows: readonly string[]): PathGrid;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { gridFromRows as i, PathGrid as n, findPath as r, FindPathOptions as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
2
|
+
import { k as diagnose } from "./loader-D7jTvDQv.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-
|
|
4
|
+
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-DL3izw8j.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { t as withoutRapierInitNoise } from "./quiet-rapier-BAJ4K94N.js";
|
|
7
7
|
//#region src/2d/physics/physics-2d.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
2
|
+
import { k as diagnose } from "./loader-D7jTvDQv.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { H as validateCollider3D, I as Area3D, L as CharacterBody3D, R as PhysicsBody3D, V as Node3D, z as RigidBody3D } from "./gameplay-
|
|
4
|
+
import { H as validateCollider3D, I as Area3D, L as CharacterBody3D, R as PhysicsBody3D, V as Node3D, z as RigidBody3D } from "./gameplay-Dtzd2itW.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { t as withoutRapierInitNoise } from "./quiet-rapier-BAJ4K94N.js";
|
|
7
|
-
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-
|
|
7
|
+
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-CNxCuhZF.js";
|
|
8
8
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
9
9
|
//#region src/3d/physics/collider-lines.ts
|
|
10
10
|
/**
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-
|
|
1
|
+
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-DsgayMsH.js";
|
|
2
2
|
import { c as JsonValue } from "./schema-CFeioQRE.js";
|
|
3
3
|
import { CSSProperties, ReactNode } from "react";
|
|
4
4
|
|
package/dist/react.js
CHANGED
|
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
|
|
|
156
156
|
pointer: latest.pointer,
|
|
157
157
|
...keyboard !== void 0 ? { keyboard } : {}
|
|
158
158
|
};
|
|
159
|
-
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-
|
|
159
|
+
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-IX5lEH0P.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DH7JI5xx.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { I as translateOn, t as registerCoreNodes } from "./register-
|
|
1
|
+
import { O as Node, k as diagnose, w as effectiveOrder } from "./loader-D7jTvDQv.js";
|
|
2
|
+
import { I as translateOn, t as registerCoreNodes } from "./register-xuSRyD6b.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
|
-
import { i as getNodeSchema, l as registerNode } from "./registry-
|
|
5
|
+
import { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
|
|
6
6
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
7
7
|
import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
|
|
8
8
|
import { AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture, Color, DynamicDrawUsage, Group, InstancedMesh, MathUtils, Matrix4, Mesh, MeshBasicMaterial, NearestFilter, NormalBlending, Object3D, PlaneGeometry, SRGBColorSpace } from "three";
|
|
@@ -302,7 +302,8 @@ var Joint2D = class extends Node2D {
|
|
|
302
302
|
},
|
|
303
303
|
target: {
|
|
304
304
|
default: "",
|
|
305
|
-
nodePath: true
|
|
305
|
+
nodePath: true,
|
|
306
|
+
required: true
|
|
306
307
|
},
|
|
307
308
|
anchor: { default: [0, 0] },
|
|
308
309
|
targetAnchor: { default: [0, 0] },
|
|
@@ -344,7 +345,13 @@ const UNIT_PLANE$2 = new PlaneGeometry(1, 1);
|
|
|
344
345
|
var Sprite2D = class extends Node2D {
|
|
345
346
|
static typeName = "Sprite2D";
|
|
346
347
|
static props = {
|
|
347
|
-
texture: {
|
|
348
|
+
texture: {
|
|
349
|
+
default: "",
|
|
350
|
+
asset: {
|
|
351
|
+
kind: "texture",
|
|
352
|
+
refOnly: true
|
|
353
|
+
}
|
|
354
|
+
},
|
|
348
355
|
anchor: { default: [.5, .5] },
|
|
349
356
|
flipX: { default: false },
|
|
350
357
|
flipY: { default: false },
|
|
@@ -422,7 +429,13 @@ var AnimatedSprite2D = class extends Sprite2D {
|
|
|
422
429
|
static typeName = "AnimatedSprite2D";
|
|
423
430
|
static signals = ["animationFinished"];
|
|
424
431
|
static props = {
|
|
425
|
-
sheet: {
|
|
432
|
+
sheet: {
|
|
433
|
+
default: "",
|
|
434
|
+
asset: {
|
|
435
|
+
kind: "spritesheet",
|
|
436
|
+
refOnly: true
|
|
437
|
+
}
|
|
438
|
+
},
|
|
426
439
|
animations: { default: {} },
|
|
427
440
|
autoplay: { default: "" }
|
|
428
441
|
};
|
|
@@ -828,7 +841,14 @@ var Label = class extends Node2D {
|
|
|
828
841
|
fontSize: { default: 16 },
|
|
829
842
|
color: { default: "#ffffff" },
|
|
830
843
|
font: { default: "monospace" },
|
|
831
|
-
align: { default: "left" }
|
|
844
|
+
align: { default: "left" },
|
|
845
|
+
opacity: {
|
|
846
|
+
default: 1,
|
|
847
|
+
range: {
|
|
848
|
+
min: 0,
|
|
849
|
+
max: 1
|
|
850
|
+
}
|
|
851
|
+
}
|
|
832
852
|
};
|
|
833
853
|
text = "";
|
|
834
854
|
fontSize = 16;
|
|
@@ -836,6 +856,16 @@ var Label = class extends Node2D {
|
|
|
836
856
|
font = "monospace";
|
|
837
857
|
/** 'left' | 'center' | 'right' — anchor of the text block on the node origin. */
|
|
838
858
|
align = "left";
|
|
859
|
+
/**
|
|
860
|
+
* 0..1, like `Sprite2D` and `ColorRect2D`.
|
|
861
|
+
*
|
|
862
|
+
* Label was the one 2D drawable without it, and the gap showed up through
|
|
863
|
+
* `FloatAway` — whose own doc names "a 2D `Label`" as a node it works on.
|
|
864
|
+
* `FloatAway` writes `opacity` when the node has one, so on a Label the
|
|
865
|
+
* number rose to full height at FULL opacity and then vanished in a single
|
|
866
|
+
* frame: the pop that behavior exists to avoid.
|
|
867
|
+
*/
|
|
868
|
+
opacity = 1;
|
|
839
869
|
quadMesh = null;
|
|
840
870
|
canvas = null;
|
|
841
871
|
lastKey = "";
|
|
@@ -863,7 +893,8 @@ var Label = class extends Node2D {
|
|
|
863
893
|
this.lastKey = key;
|
|
864
894
|
this.rasterize();
|
|
865
895
|
}
|
|
866
|
-
quad.visible =
|
|
896
|
+
quad.visible = this.opacity > 0;
|
|
897
|
+
quad.material.opacity = this.opacity;
|
|
867
898
|
quad.renderOrder = this.effectiveRenderOrder;
|
|
868
899
|
}
|
|
869
900
|
rasterize() {
|
|
@@ -1306,7 +1337,13 @@ var TileMap2D = class extends Node2D {
|
|
|
1306
1337
|
static typeName = "TileMap2D";
|
|
1307
1338
|
static props = {
|
|
1308
1339
|
/** Atlas texture asset ref; tiles are tileSize×tileSize squares in it. */
|
|
1309
|
-
texture: {
|
|
1340
|
+
texture: {
|
|
1341
|
+
default: "",
|
|
1342
|
+
asset: {
|
|
1343
|
+
kind: "texture",
|
|
1344
|
+
refOnly: true
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1310
1347
|
tileSize: { default: 32 },
|
|
1311
1348
|
/** Atlas columns; 0 = derive from the texture width. */
|
|
1312
1349
|
columns: { default: 0 },
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { C as
|
|
2
|
+
import { C as ORDER_GROUP_BASE, E as InputMap, O as Node, S as createSaveStore, T as resolveOrderGroups, V as Signal, b as restoreBehaviors, k as diagnose, y as captureBehaviors } from "./loader-D7jTvDQv.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
|
-
import { l as registerNode } from "./registry-
|
|
5
|
+
import { l as registerNode } from "./registry-CF70EArN.js";
|
|
6
6
|
//#region src/core/audio/buses.ts
|
|
7
7
|
const AUDIO_LOG_LIMIT = 200;
|
|
8
8
|
var AudioBuses = class {
|
|
@@ -612,6 +612,16 @@ const SFX_PRESETS = {
|
|
|
612
612
|
}
|
|
613
613
|
};
|
|
614
614
|
const SFX_PRESET_NAMES = Object.keys(SFX_PRESETS);
|
|
615
|
+
/**
|
|
616
|
+
* How long a preset lasts, in seconds — the same `attack + sustain + decay`
|
|
617
|
+
* `synthSfx` uses to size its buffer.
|
|
618
|
+
*
|
|
619
|
+
* `pitch` deliberately does not enter into it: it is a frequency multiplier,
|
|
620
|
+
* not a playback rate, so a preset played an octave up is the same length.
|
|
621
|
+
*/
|
|
622
|
+
function sfxDuration(params) {
|
|
623
|
+
return params.attack + params.sustain + params.decay;
|
|
624
|
+
}
|
|
615
625
|
const TWO_PI = Math.PI * 2;
|
|
616
626
|
/**
|
|
617
627
|
* Render a preset to mono PCM in [-1, 1]. PURE: identical inputs → identical
|
|
@@ -1369,6 +1379,14 @@ var HudLayer = class extends Node {
|
|
|
1369
1379
|
* widget (an icon inside a slot), so the walk upward is the point.
|
|
1370
1380
|
*/
|
|
1371
1381
|
const widgetOf = /* @__PURE__ */ new WeakMap();
|
|
1382
|
+
/** The nearest ancestor widget that actually accepts a drop. */
|
|
1383
|
+
function dropTargetFromElement(el) {
|
|
1384
|
+
for (let n = el; n; n = n.parentElement) {
|
|
1385
|
+
const found = widgetOf.get(n);
|
|
1386
|
+
if (found?.dropTarget) return found;
|
|
1387
|
+
}
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1372
1390
|
function widgetFromElement(el) {
|
|
1373
1391
|
for (let n = el; n; n = n.parentElement) {
|
|
1374
1392
|
const found = widgetOf.get(n);
|
|
@@ -1378,6 +1396,8 @@ function widgetFromElement(el) {
|
|
|
1378
1396
|
}
|
|
1379
1397
|
/** The drag in flight, if any. One pointer, one drag. */
|
|
1380
1398
|
let dragging = null;
|
|
1399
|
+
/** The drop target the dragged widget came OUT of — putting it back is a no-op. */
|
|
1400
|
+
let draggingFrom = null;
|
|
1381
1401
|
/** Shared plumbing: mount into the parent HudLayer's anchor slot. */
|
|
1382
1402
|
var HudWidgetBase = class extends Node {
|
|
1383
1403
|
/**
|
|
@@ -1495,6 +1515,7 @@ var HudWidgetBase = class extends Node {
|
|
|
1495
1515
|
event.preventDefault();
|
|
1496
1516
|
el.setPointerCapture?.(event.pointerId);
|
|
1497
1517
|
dragging = this;
|
|
1518
|
+
draggingFrom = dropTargetFromElement(el.parentElement);
|
|
1498
1519
|
el.style.opacity = "0.6";
|
|
1499
1520
|
this.emit("dragStarted", this);
|
|
1500
1521
|
});
|
|
@@ -1502,9 +1523,12 @@ var HudWidgetBase = class extends Node {
|
|
|
1502
1523
|
if (dragging !== this) return;
|
|
1503
1524
|
el.style.opacity = "";
|
|
1504
1525
|
el.releasePointerCapture?.(event.pointerId);
|
|
1505
|
-
const
|
|
1526
|
+
const under = document.elementFromPoint?.(event.clientX, event.clientY) ?? null;
|
|
1527
|
+
const target = dropTargetFromElement(under) ?? widgetFromElement(under);
|
|
1528
|
+
const origin = draggingFrom;
|
|
1506
1529
|
dragging = null;
|
|
1507
|
-
|
|
1530
|
+
draggingFrom = null;
|
|
1531
|
+
if (target && target !== this && target !== origin && target.dropTarget) {
|
|
1508
1532
|
this.emit("droppedOn", target);
|
|
1509
1533
|
target.emit("dropped", this);
|
|
1510
1534
|
} else this.emit("dragCancelled", this);
|
|
@@ -1584,6 +1608,18 @@ var HudWidgetBase = class extends Node {
|
|
|
1584
1608
|
* was empty at bake time and the English was permanent even for a game that
|
|
1585
1609
|
* boots in another language.
|
|
1586
1610
|
*/
|
|
1611
|
+
/**
|
|
1612
|
+
* What this widget actually PAINTS, when that differs from its props.
|
|
1613
|
+
*
|
|
1614
|
+
* A headless capture printed `text="@t:menu.start"` — byte-identical in
|
|
1615
|
+
* every language — so a passing capture proved nothing about localization
|
|
1616
|
+
* and a broken translation was invisible to every check the engine has.
|
|
1617
|
+
* `incanto-frame` reads the WebGL buffer and cannot read DOM text at all.
|
|
1618
|
+
*
|
|
1619
|
+
* `undefined` when the painted words ARE the prop: recording it twice would
|
|
1620
|
+
* be noise on every widget in a game that never localizes anything.
|
|
1621
|
+
*/
|
|
1622
|
+
_paintedText() {}
|
|
1587
1623
|
_labelText() {
|
|
1588
1624
|
const label = this.label;
|
|
1589
1625
|
return typeof label === "string" ? this._t(label) : "";
|
|
@@ -1642,6 +1678,10 @@ var UiText = class extends HudWidgetBase {
|
|
|
1642
1678
|
if (this.format && this.slot !== null) return this._t(this.format).replace("{}", this.slot);
|
|
1643
1679
|
return this._t(this.text);
|
|
1644
1680
|
}
|
|
1681
|
+
_paintedText() {
|
|
1682
|
+
const painted = this.shown;
|
|
1683
|
+
return painted === this.text ? void 0 : painted;
|
|
1684
|
+
}
|
|
1645
1685
|
_build() {
|
|
1646
1686
|
const el = document.createElement("div");
|
|
1647
1687
|
el.style.cssText = this.look();
|
|
@@ -1812,6 +1852,7 @@ var UiBanner = class extends HudWidgetBase {
|
|
|
1812
1852
|
show(text, opts) {
|
|
1813
1853
|
this.queue.push({
|
|
1814
1854
|
text,
|
|
1855
|
+
source: text,
|
|
1815
1856
|
color: opts?.color ?? "#ffffff",
|
|
1816
1857
|
seconds: opts?.seconds ?? this.seconds
|
|
1817
1858
|
});
|
|
@@ -1844,6 +1885,11 @@ var UiBanner = class extends HudWidgetBase {
|
|
|
1844
1885
|
this._element.style.opacity = opacity;
|
|
1845
1886
|
}
|
|
1846
1887
|
if (this.current) {
|
|
1888
|
+
const next = this._t(this.current.source);
|
|
1889
|
+
if (next !== this.current.text) {
|
|
1890
|
+
this.current.text = next;
|
|
1891
|
+
if (this._element) this._element.textContent = next;
|
|
1892
|
+
}
|
|
1847
1893
|
if (this.current.seconds > 0) {
|
|
1848
1894
|
this.remaining -= dt;
|
|
1849
1895
|
if (this.remaining <= 0) {
|
|
@@ -1854,7 +1900,7 @@ var UiBanner = class extends HudWidgetBase {
|
|
|
1854
1900
|
}
|
|
1855
1901
|
if (!this.current && this.queue.length > 0) {
|
|
1856
1902
|
this.current = this.queue.shift();
|
|
1857
|
-
this.current.text = this._t(this.current.
|
|
1903
|
+
this.current.text = this._t(this.current.source);
|
|
1858
1904
|
this.remaining = this.current.seconds;
|
|
1859
1905
|
if (this._element) {
|
|
1860
1906
|
this._element.textContent = this.current.text;
|
|
@@ -2441,6 +2487,7 @@ var Engine = class {
|
|
|
2441
2487
|
this.input.clear();
|
|
2442
2488
|
this._time = 0;
|
|
2443
2489
|
this._unscaledTime = 0;
|
|
2490
|
+
this.timeScale = 1;
|
|
2444
2491
|
if (scene.input) this.input.declare(scene.input);
|
|
2445
2492
|
if (scene.strings) this.locale.load(scene.strings);
|
|
2446
2493
|
this.orderGroups = resolveOrderGroups(scene.orderGroups);
|
|
@@ -2722,7 +2769,7 @@ function createElement() {
|
|
|
2722
2769
|
}
|
|
2723
2770
|
/**
|
|
2724
2771
|
* One sound. `play()` (or `autoplay: true`) starts it; `finished` fires when
|
|
2725
|
-
* it ends. Browsers block audio before the first user gesture — a blocked
|
|
2772
|
+
* it ends — for a procedural preset as well as a `src` clip. Browsers block audio before the first user gesture — a blocked
|
|
2726
2773
|
* play marks `pendingGesture`; `createGame` retries pending players on the
|
|
2727
2774
|
* first pointer/key gesture automatically.
|
|
2728
2775
|
*
|
|
@@ -2779,10 +2826,12 @@ var AudioPlayer = class extends Node {
|
|
|
2779
2826
|
/** Start on the first frame in the tree (subject to the gesture policy). */
|
|
2780
2827
|
autoplay = false;
|
|
2781
2828
|
/**
|
|
2782
|
-
*
|
|
2783
|
-
*
|
|
2784
|
-
*
|
|
2785
|
-
*
|
|
2829
|
+
* Positional audio: the sound pans + attenuates by the emitter's world
|
|
2830
|
+
* position relative to the active camera (the listener). Default false →
|
|
2831
|
+
* identical non-spatial behavior.
|
|
2832
|
+
*
|
|
2833
|
+
* Both dimensions. A 2D scene measures in PIXELS, so the distances below —
|
|
2834
|
+
* metre-shaped defaults — need setting there; `auditScene` says so.
|
|
2786
2835
|
*/
|
|
2787
2836
|
spatial = false;
|
|
2788
2837
|
/** Distance at which spatial gain is full; closer never gets louder. */
|
|
@@ -2816,6 +2865,21 @@ var AudioPlayer = class extends Node {
|
|
|
2816
2865
|
loadError = null;
|
|
2817
2866
|
element = null;
|
|
2818
2867
|
_playing = false;
|
|
2868
|
+
/**
|
|
2869
|
+
* `engine.unscaledTime` at which the preset currently sounding ends.
|
|
2870
|
+
*
|
|
2871
|
+
* A preset used to be fire-and-forget: `playing` stayed false through a sound
|
|
2872
|
+
* that was audibly playing, and `finished` — a signal this node DECLARES, so
|
|
2873
|
+
* a connection to it loads clean — never fired at all. Wiring "when the coin
|
|
2874
|
+
* chime ends, free the pickup" to a preset player produced a wire that is
|
|
2875
|
+
* dead for the life of the game and says nothing.
|
|
2876
|
+
*
|
|
2877
|
+
* The end is known exactly: `attack + sustain + decay` is the length
|
|
2878
|
+
* `synthSfx` sizes its buffer to. Measured on the UNSCALED clock because a
|
|
2879
|
+
* sound does not slow down when the game does, and a paused game still hears
|
|
2880
|
+
* the tail of the hit that paused it.
|
|
2881
|
+
*/
|
|
2882
|
+
presetEndsAt = null;
|
|
2819
2883
|
autoplayed = false;
|
|
2820
2884
|
/** Last spatial pose pushed by the 3D adapter (null until/unless spatial). */
|
|
2821
2885
|
_spatialPose = null;
|
|
@@ -2918,15 +2982,18 @@ var AudioPlayer = class extends Node {
|
|
|
2918
2982
|
}
|
|
2919
2983
|
/**
|
|
2920
2984
|
* Procedural-SFX path: synthesize the preset and fire it through WebAudio
|
|
2921
|
-
* (low-latency, overlap-friendly).
|
|
2922
|
-
*
|
|
2923
|
-
*
|
|
2924
|
-
*
|
|
2985
|
+
* (low-latency, overlap-friendly). Headless (no AudioContext) plays nothing —
|
|
2986
|
+
* but still reports `playing` and still emits `finished` on schedule, because
|
|
2987
|
+
* the length is arithmetic, not a device. WebAudio needs a gesture; a
|
|
2988
|
+
* suspended context is resumed by the same unlock listener as `src` players.
|
|
2925
2989
|
*/
|
|
2926
2990
|
playPreset() {
|
|
2927
2991
|
const params = SFX_PRESETS[this.preset];
|
|
2928
2992
|
if (!params) return;
|
|
2929
|
-
const
|
|
2993
|
+
const engine = this.tree?.engine;
|
|
2994
|
+
this._playing = true;
|
|
2995
|
+
this.presetEndsAt = (engine?.unscaledTime ?? 0) + sfxDuration(params);
|
|
2996
|
+
const sfx = engine?.sfx;
|
|
2930
2997
|
if (!sfx) return;
|
|
2931
2998
|
sfx.play(params, this.gain(), {
|
|
2932
2999
|
pitch: this.pitch,
|
|
@@ -2952,6 +3019,7 @@ var AudioPlayer = class extends Node {
|
|
|
2952
3019
|
this.element.pause();
|
|
2953
3020
|
this.element.currentTime = 0;
|
|
2954
3021
|
}
|
|
3022
|
+
this.presetEndsAt = null;
|
|
2955
3023
|
this._playing = false;
|
|
2956
3024
|
this.pendingGesture = false;
|
|
2957
3025
|
}
|
|
@@ -2964,6 +3032,13 @@ var AudioPlayer = class extends Node {
|
|
|
2964
3032
|
this.autoplayed = true;
|
|
2965
3033
|
this.play();
|
|
2966
3034
|
}
|
|
3035
|
+
if (this.presetEndsAt !== null) {
|
|
3036
|
+
if ((this.tree?.engine?.unscaledTime ?? 0) >= this.presetEndsAt) {
|
|
3037
|
+
this.presetEndsAt = null;
|
|
3038
|
+
this._playing = false;
|
|
3039
|
+
this.emit("finished");
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2967
3042
|
if (this.element && this._playing) {
|
|
2968
3043
|
this.element.volume = this.gain() * this.spatialElementGain();
|
|
2969
3044
|
this.element.loop = this.loop;
|
|
@@ -3107,10 +3182,14 @@ var UiDialogue = class extends HudWidgetBase {
|
|
|
3107
3182
|
}
|
|
3108
3183
|
/** Queue a line; optional `choices` renders buttons after the line types out. */
|
|
3109
3184
|
say(speaker, text, choices) {
|
|
3110
|
-
|
|
3185
|
+
const source = {
|
|
3111
3186
|
speaker,
|
|
3112
3187
|
text,
|
|
3113
3188
|
choices: choices ?? null
|
|
3189
|
+
};
|
|
3190
|
+
this.queue.push({
|
|
3191
|
+
...source,
|
|
3192
|
+
source
|
|
3114
3193
|
});
|
|
3115
3194
|
}
|
|
3116
3195
|
/**
|
|
@@ -3164,13 +3243,22 @@ var UiDialogue = class extends HudWidgetBase {
|
|
|
3164
3243
|
box.addEventListener("click", () => this.advance());
|
|
3165
3244
|
return box;
|
|
3166
3245
|
}
|
|
3246
|
+
/** The locale `current` was resolved in, so a switch is one compare away. */
|
|
3247
|
+
resolvedIn = "\0";
|
|
3248
|
+
/** Re-read the live line from its untouched source. */
|
|
3249
|
+
resolveCurrent() {
|
|
3250
|
+
const line = this.current;
|
|
3251
|
+
if (!line) return;
|
|
3252
|
+
line.text = this._t(line.source.text);
|
|
3253
|
+
line.speaker = this._t(line.source.speaker);
|
|
3254
|
+
line.choices = line.source.choices ? line.source.choices.map((c) => this._t(c)) : null;
|
|
3255
|
+
this.resolvedIn = this.tree?.engine?.locale.locale ?? "";
|
|
3256
|
+
}
|
|
3167
3257
|
update(dt) {
|
|
3168
3258
|
super.update(dt);
|
|
3169
3259
|
if (!this.current && this.queue.length > 0) {
|
|
3170
3260
|
this.current = this.queue.shift();
|
|
3171
|
-
this.
|
|
3172
|
-
this.current.speaker = this._t(this.current.speaker);
|
|
3173
|
-
if (this.current.choices) this.current.choices = this.current.choices.map((c) => this._t(c));
|
|
3261
|
+
this.resolveCurrent();
|
|
3174
3262
|
this.revealed = this.charsPerSecond <= 0 ? this.current.text.length : 0;
|
|
3175
3263
|
this.emit("lineShown", this.current.text);
|
|
3176
3264
|
if (this._element) {
|
|
@@ -3180,6 +3268,13 @@ var UiDialogue = class extends HudWidgetBase {
|
|
|
3180
3268
|
}
|
|
3181
3269
|
if (this._element) this._element.style.display = this.visible && this.current ? "block" : "none";
|
|
3182
3270
|
if (!this.current) return;
|
|
3271
|
+
if ((this.tree?.engine?.locale.locale ?? "") !== this.resolvedIn) {
|
|
3272
|
+
const before = this.current.text.length;
|
|
3273
|
+
const progress = before > 0 ? this.revealed / before : 1;
|
|
3274
|
+
this.resolveCurrent();
|
|
3275
|
+
this.revealed = Math.round(progress * this.current.text.length);
|
|
3276
|
+
if (this.speakerEl) this.speakerEl.textContent = this.current.speaker;
|
|
3277
|
+
}
|
|
3183
3278
|
const wasTyping = this.revealed < this.current.text.length;
|
|
3184
3279
|
if (wasTyping) this.revealed = Math.min(this.current.text.length, this.revealed + this.charsPerSecond * dt);
|
|
3185
3280
|
const doneTyping = this.revealed >= this.current.text.length;
|
|
@@ -3330,7 +3425,10 @@ var UiImage = class extends HudWidgetBase {
|
|
|
3330
3425
|
static typeName = "UiImage";
|
|
3331
3426
|
static props = {
|
|
3332
3427
|
...HudWidgetBase.props,
|
|
3333
|
-
src: {
|
|
3428
|
+
src: {
|
|
3429
|
+
default: "",
|
|
3430
|
+
asset: { kind: "texture" }
|
|
3431
|
+
},
|
|
3334
3432
|
width: { default: 48 },
|
|
3335
3433
|
height: { default: 48 },
|
|
3336
3434
|
/** How the picture fills its box — `contain` never crops. */
|
|
@@ -3943,4 +4041,4 @@ function registerCoreNodes() {
|
|
|
3943
4041
|
registerNode(UiMuteToggle);
|
|
3944
4042
|
}
|
|
3945
4043
|
//#endregion
|
|
3946
|
-
export { UiBar as A, ROLLOFF_MODELS as B, readDeviceHints as C, HudLayer as D, EffectLog as E, suggestLocale as F,
|
|
4044
|
+
export { UiBar as A, ROLLOFF_MODELS as B, readDeviceHints as C, HudLayer as D, EffectLog as E, suggestLocale as F, sfxDuration as G, spatialPan as H, translateOn as I, WebAudioMusicBackend as J, synthSfx as K, translationKey as L, BASE_LOCALE as M, Localization as N, HudWidgetBase as O, T_PREFIX as P, SfxEngine as R, qualityRendering as S, LogManager as T, SFX_PRESETS as U, spatialGain as V, SFX_PRESET_NAMES as W, fadeGain as X, crossfadeGains as Y, AudioBuses as Z, Engine as _, UiMuteToggle as a, qualityCaps as b, UiRenderScaleSelect as c, UiToggle as d, UiVolumeSlider as f, AudioPlayer as g, UiDialogue as h, UiLanguageSelect as i, UiText as j, UiBanner as k, UiSelect as l, UiButton as m, UiFrameCapSelect as n, UiPanel as o, Timer as p, MusicManager as q, UiImage as r, UiQualitySelect as s, registerCoreNodes as t, UiSlider as u, engine_exports as v, suggestQuality as w, qualityEnvironment as x, Settings as y, isAudioContextAvailable as z };
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
2
|
import { r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
|
|
3
|
+
//#region src/core/prop-range.ts
|
|
4
|
+
function describe(range) {
|
|
5
|
+
const { min, max, exclusiveMin, allow } = range;
|
|
6
|
+
let body;
|
|
7
|
+
if (min !== void 0 && max !== void 0) body = `${min}..${max}`;
|
|
8
|
+
else if (min !== void 0) body = exclusiveMin ? `greater than ${min}` : `at least ${min}`;
|
|
9
|
+
else if (max !== void 0) body = `at most ${max}`;
|
|
10
|
+
else body = "a finite number";
|
|
11
|
+
return allow && allow.length > 0 ? `${body} (or ${allow.join(", ")})` : body;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Throws `PROP_TYPE_MISMATCH` when a number falls outside its documented range.
|
|
15
|
+
*
|
|
16
|
+
* A non-number is ignored: the kind check has already run and reporting the
|
|
17
|
+
* same value twice, under two codes, tells its reader nothing new.
|
|
18
|
+
*
|
|
19
|
+
* @param value the authored value
|
|
20
|
+
* @param label `Type.prop`, for the message
|
|
21
|
+
* @param range what the prop documents
|
|
22
|
+
*/
|
|
23
|
+
function validatePropRange(value, label, range) {
|
|
24
|
+
if (typeof value !== "number") return;
|
|
25
|
+
if (range.allow?.includes(value)) return;
|
|
26
|
+
if (!Number.isFinite(value)) throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${label}' must be a finite number, got ${value}.`, { prop: label });
|
|
27
|
+
const belowMin = range.min !== void 0 && (range.exclusiveMin ? value <= range.min : value < range.min);
|
|
28
|
+
const aboveMax = range.max !== void 0 && value > range.max;
|
|
29
|
+
if (!belowMin && !aboveMax) return;
|
|
30
|
+
throw new IncantoError("PROP_TYPE_MISMATCH", `Prop '${label}' must be ${describe(range)}, got ${value}.`, { prop: label });
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
3
33
|
//#region src/core/registry.ts
|
|
4
34
|
/**
|
|
5
35
|
* Validate a prop value against its schema default:
|
|
@@ -120,7 +150,10 @@ function mergeStaticAliases(ctor) {
|
|
|
120
150
|
*/
|
|
121
151
|
function applySchemaProps(target, schema, props, label, aliases = {}, extraOptions = {}) {
|
|
122
152
|
for (const [key, def] of Object.entries(schema)) target[key] = jsonClone(def.default);
|
|
123
|
-
if (
|
|
153
|
+
if (props) applyGivenProps(target, schema, props, label, aliases, extraOptions);
|
|
154
|
+
requireNonEmpty(target, schema, label);
|
|
155
|
+
}
|
|
156
|
+
function applyGivenProps(target, schema, props, label, aliases, extraOptions) {
|
|
124
157
|
for (const [rawKey, value] of Object.entries(props)) {
|
|
125
158
|
const key = schema[rawKey] ? rawKey : aliases[rawKey] ?? rawKey;
|
|
126
159
|
const def = schema[key];
|
|
@@ -135,18 +168,37 @@ function applySchemaProps(target, schema, props, label, aliases = {}, extraOptio
|
|
|
135
168
|
const extra = extraOptions[key];
|
|
136
169
|
const options = def.options && extra && extra.length > 0 ? [...def.options, ...extra] : def.options;
|
|
137
170
|
validatePropValue(value, def.default, `${label}.${key}`, options);
|
|
171
|
+
if (def.range) validatePropRange(value, `${label}.${key}`, def.range);
|
|
138
172
|
target[key] = jsonClone(value);
|
|
139
173
|
}
|
|
174
|
+
}
|
|
175
|
+
function requireNonEmpty(target, schema, label) {
|
|
140
176
|
for (const [key, def] of Object.entries(schema)) {
|
|
141
177
|
if (!def.required) continue;
|
|
142
|
-
|
|
143
|
-
|
|
178
|
+
if (!isEmptyValue(target[key])) continue;
|
|
179
|
+
throw new IncantoError("PROP_TYPE_MISMATCH", `'${label}' needs a "${key}" — it is empty.`, {
|
|
144
180
|
prop: key,
|
|
145
181
|
nodeType: label
|
|
146
182
|
});
|
|
147
183
|
}
|
|
148
184
|
}
|
|
149
185
|
/**
|
|
186
|
+
* "Not a configuration" — what `required` refuses.
|
|
187
|
+
*
|
|
188
|
+
* The first cut only knew about `''`, which is what the two props that
|
|
189
|
+
* introduced the flag hold. Three of the ones declared since default to an
|
|
190
|
+
* ARRAY — `MoveTo.to`, `Patrol.points`, `WaveSpawner.waves` — and for those the
|
|
191
|
+
* flag was inert: a `MoveTo` with no `to` loaded clean and moved nowhere, which
|
|
192
|
+
* is exactly the failure the flag was added to stop. Found by running the
|
|
193
|
+
* shipped package as a consumer instead of trusting the declaration.
|
|
194
|
+
*/
|
|
195
|
+
function isEmptyValue(value) {
|
|
196
|
+
if (value === "" || value === void 0 || value === null) return true;
|
|
197
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
198
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
150
202
|
* Instantiate a registered type, assign schema defaults (cloned), then the
|
|
151
203
|
* given props — validating every key and its JSON kind against the default.
|
|
152
204
|
*/
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { b as Engine } from "./behavior-
|
|
1
|
+
import { b as Engine } from "./behavior-DsgayMsH.js";
|
|
2
2
|
import { s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/core/audit.d.ts
|
|
5
5
|
/** Human-readable warnings (empty = clean). Pure JSON walk, no registry. */
|
|
6
|
-
|
|
6
|
+
interface AuditOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Every locale table the whole PROJECT declares, unioned.
|
|
9
|
+
*
|
|
10
|
+
* Localization tables MERGE across scenes — a game's shared UI strings live
|
|
11
|
+
* in the scene it boots from, and a level that adds three lines of its own
|
|
12
|
+
* does not wipe them. Auditing one file in isolation therefore reported a key
|
|
13
|
+
* declared in the boot scene as "nothing declares" it, and told its author to
|
|
14
|
+
* add a string they already have. The checker passes the corpus in when it
|
|
15
|
+
* has one.
|
|
16
|
+
*/
|
|
17
|
+
declaredElsewhere?: Record<string, Record<string, string>>;
|
|
18
|
+
}
|
|
19
|
+
declare function auditScene(scene: JsonObject, opts?: AuditOptions): string[];
|
|
7
20
|
//#endregion
|
|
8
21
|
//#region src/core/errors.d.ts
|
|
9
22
|
/**
|
|
@@ -12,7 +25,7 @@ declare function auditScene(scene: JsonObject): string[];
|
|
|
12
25
|
* Incanto fails loudly with machine-readable codes and messages that list valid
|
|
13
26
|
* alternatives — AI agents self-correct on hard failures, not warnings.
|
|
14
27
|
*/
|
|
15
|
-
type IncantoErrorCode = "BAD_FORMAT" | "BAD_NODE_PATH" | "DANGLING_CONNECTION" | "DUPLICATE_BEHAVIOR" | "DUPLICATE_NODE_TYPE" | "DUPLICATE_UNIQUE_NAME" | "DUPLICATE_UID" | "NODE_NOT_FOUND" | "PROP_TYPE_MISMATCH" | "TREE_VIOLATION" | "UNKNOWN_ANIMATION" | "UNKNOWN_ASSET" | "UNKNOWN_CONSTANT" | "UNKNOWN_BEHAVIOR" | "UNKNOWN_HANDLER" | "UNKNOWN_NODE_TYPE" | "UNKNOWN_PROP" | "UNKNOWN_SIGNAL" | "UNRESOLVED_INSTANCE";
|
|
28
|
+
type IncantoErrorCode = "AMBIGUOUS_HANDLER" | "BAD_FORMAT" | "BAD_NODE_PATH" | "DANGLING_CONNECTION" | "DUPLICATE_BEHAVIOR" | "DUPLICATE_NODE_TYPE" | "DUPLICATE_UNIQUE_NAME" | "DUPLICATE_UID" | "NODE_NOT_FOUND" | "PROP_TYPE_MISMATCH" | "TREE_VIOLATION" | "UNKNOWN_ANIMATION" | "UNKNOWN_ASSET" | "UNKNOWN_CONSTANT" | "UNKNOWN_BEHAVIOR" | "UNKNOWN_HANDLER" | "UNKNOWN_NODE_TYPE" | "UNKNOWN_PROP" | "UNKNOWN_SIGNAL" | "UNRESOLVED_INSTANCE";
|
|
16
29
|
/**
|
|
17
30
|
* Structured context mirrored from the prose message — tools and agents parse
|
|
18
31
|
* THESE instead of regexing the message (which is for humans and may reword).
|