incanto 0.7.0 → 0.8.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 +6 -4
- package/dist/2d.d.ts +93 -3
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +45 -4
- package/dist/3d.js +4 -4
- package/dist/{audio-player-VSjk_vG8.d.ts → audio-player-Dyjg5k92.d.ts} +1 -1
- package/dist/audit-C6rMyict.js +58 -0
- package/dist/{behavior-e3kAmPGC.d.ts → behavior-Bod1AyJS.d.ts} +211 -174
- package/dist/{create-game-CEFoFN8d.js → create-game-66c4iYJE.js} +76 -6
- package/dist/{create-game-X5iRu6pf.js → create-game-BNDSbhy-.js} +88 -6
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +3 -0
- package/dist/{errors-BMFaY68Q.d.ts → errors-1dXlIwoR.d.ts} +7 -1
- package/dist/{gameplay-CDFgSG6z.js → gameplay-DPMgZk9W.js} +108 -1
- package/dist/gameplay.d.ts +44 -3
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +151 -9
- package/dist/index.js +189 -4
- package/dist/{loader-y_X4zYO0.d.ts → loader-BcUDfNHn.d.ts} +1 -1
- package/dist/net.d.ts +46 -2
- package/dist/net.js +54 -2
- package/dist/particle-sim-CyUU7HVU.js +281 -0
- package/dist/{physics-2d-DmQ540uR.js → physics-2d-q2N362ph.js} +45 -4
- package/dist/{physics-3d-CDjuhtt_.js → physics-3d-CvHr31d4.js} +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-CscQqB7V.js → register-Cbs7QxoV.js} +139 -4
- package/dist/{register-ClKnoILk.js → register-Cqjxrfq0.js} +254 -4
- package/dist/{register-C35HDZpm.js → register-CxmuI9FL.js} +1 -1
- package/dist/{particle-sim-CrTE7c02.js → register-DRPIjrKG.js} +1185 -278
- package/dist/test.d.ts +4 -10
- package/dist/test.js +11 -16
- package/editor/assets/{agent8-1WJU-yXr.js → agent8-B8QnWCeP.js} +1 -1
- package/editor/assets/{index-DzYFgZbl.js → index-CVhnNkb3.js} +81 -81
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +427 -0
- package/skills/incanto-3d-character.md +14 -0
- package/skills/incanto-audio.md +23 -0
- package/skills/incanto-building-2d-games.md +31 -0
- package/skills/incanto-building-3d-games.md +21 -0
- package/skills/incanto-gameplay-behaviors.md +28 -0
- package/skills/incanto-hud.md +24 -0
- package/skills/incanto-multiplayer.md +27 -0
- package/skills/incanto-node-reference.md +73 -0
- package/skills/incanto-physics-and-input.md +9 -0
- package/skills/incanto-verifying-your-game.md +40 -0
- package/dist/register-Dl_ixIJe.js +0 -834
package/dist/debug.js
CHANGED
|
@@ -328,6 +328,7 @@ var DebugOverlay = class {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
dispose() {
|
|
331
|
+
this.engine.debugSelection = null;
|
|
331
332
|
this.setConsoleCapture(false);
|
|
332
333
|
for (const cleanup of this.cleanups) cleanup();
|
|
333
334
|
for (const id of [...this.panels.keys()]) this.close(id);
|
|
@@ -471,6 +472,7 @@ var DebugOverlay = class {
|
|
|
471
472
|
}
|
|
472
473
|
row.addEventListener("click", () => {
|
|
473
474
|
this.selected = node;
|
|
475
|
+
this.engine.debugSelection = node;
|
|
474
476
|
this.open("inspector");
|
|
475
477
|
this.renderExplorer();
|
|
476
478
|
this.renderInspector();
|
|
@@ -496,6 +498,7 @@ var DebugOverlay = class {
|
|
|
496
498
|
let node = this.selected;
|
|
497
499
|
if (node && node.tree === null) {
|
|
498
500
|
this.selected = null;
|
|
501
|
+
this.engine.debugSelection = null;
|
|
499
502
|
node = null;
|
|
500
503
|
}
|
|
501
504
|
if (!node) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { s as JsonObject } from "./schema-CcoWb32N.js";
|
|
2
|
+
|
|
3
|
+
//#region src/core/audit.d.ts
|
|
4
|
+
/** Human-readable warnings (empty = clean). Pure JSON walk, no registry. */
|
|
5
|
+
declare function auditScene(scene: JsonObject): string[];
|
|
6
|
+
//#endregion
|
|
1
7
|
//#region src/core/errors.d.ts
|
|
2
8
|
/**
|
|
3
9
|
* Stable error codes for every hard failure in the engine.
|
|
@@ -30,4 +36,4 @@ declare class IncantoError extends Error {
|
|
|
30
36
|
constructor(code: IncantoErrorCode, message: string, details?: IncantoErrorDetails);
|
|
31
37
|
}
|
|
32
38
|
//#endregion
|
|
33
|
-
export { IncantoErrorCode as n, IncantoErrorDetails as r, IncantoError as t };
|
|
39
|
+
export { auditScene as i, IncantoErrorCode as n, IncantoErrorDetails as r, IncantoError as t };
|
|
@@ -480,6 +480,39 @@ function restartScene(engine) {
|
|
|
480
480
|
engine.setScene(loadScene(jsonClone(source)));
|
|
481
481
|
}
|
|
482
482
|
/**
|
|
483
|
+
* Swap to another scene behind a black fade (title→game→next level).
|
|
484
|
+
* Headless (no DOM) the swap is immediate. Restores timeScale to 1.
|
|
485
|
+
*/
|
|
486
|
+
function goToScene(engine, sceneJson, opts) {
|
|
487
|
+
const fade = opts?.fadeSeconds ?? .4;
|
|
488
|
+
const swap = () => {
|
|
489
|
+
engine.timeScale = 1;
|
|
490
|
+
engine.setScene(loadScene(jsonClone(sceneJson)));
|
|
491
|
+
};
|
|
492
|
+
if (typeof document === "undefined" || fade <= 0) {
|
|
493
|
+
swap();
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const id = "incanto-scene-fade";
|
|
497
|
+
let el = document.getElementById(id);
|
|
498
|
+
if (!el) {
|
|
499
|
+
el = document.createElement("div");
|
|
500
|
+
el.id = id;
|
|
501
|
+
el.style.cssText = "position:fixed;inset:0;z-index:10001;background:#000;opacity:0;pointer-events:none;";
|
|
502
|
+
document.body.appendChild(el);
|
|
503
|
+
}
|
|
504
|
+
el.style.transition = `opacity ${fade / 2}s`;
|
|
505
|
+
el.style.opacity = "1";
|
|
506
|
+
setTimeout(() => {
|
|
507
|
+
swap();
|
|
508
|
+
const out = document.getElementById(id);
|
|
509
|
+
if (out) {
|
|
510
|
+
out.style.opacity = "0";
|
|
511
|
+
setTimeout(() => out.remove(), fade * 500 + 60);
|
|
512
|
+
}
|
|
513
|
+
}, fade * 500 + 30);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
483
516
|
* The win/lose/restart state machine 6+ examples hand-rolled as `over`/`win`
|
|
484
517
|
* booleans. Attach to any node (the scene root is natural):
|
|
485
518
|
*
|
|
@@ -531,6 +564,11 @@ var GameFlow = class extends Behavior {
|
|
|
531
564
|
this.thaw();
|
|
532
565
|
restartScene(this.engine);
|
|
533
566
|
}
|
|
567
|
+
/** Fade to another scene (next level, back to title). */
|
|
568
|
+
goToScene(sceneJson, opts) {
|
|
569
|
+
this.thaw();
|
|
570
|
+
goToScene(this.engine, sceneJson, opts);
|
|
571
|
+
}
|
|
534
572
|
transition(state, text, color) {
|
|
535
573
|
if (this.state === "gameover" || this.state === "won") return;
|
|
536
574
|
this.state = state;
|
|
@@ -986,6 +1024,74 @@ var Oscillate = class extends Behavior {
|
|
|
986
1024
|
}
|
|
987
1025
|
};
|
|
988
1026
|
//#endregion
|
|
1027
|
+
//#region src/gameplay/path-follow.ts
|
|
1028
|
+
/**
|
|
1029
|
+
* Walk a list of waypoints at a constant speed, then stop — the delivery
|
|
1030
|
+
* end of `findPath`:
|
|
1031
|
+
*
|
|
1032
|
+
* const cells = findPath(grid, start, goal);
|
|
1033
|
+
* (npc.behavior as PathFollow).setPath(cells.map(([cx, cy]) => [cx * TILE, cy * TILE]));
|
|
1034
|
+
*
|
|
1035
|
+
* Waypoints are world positions in the node's own units (2D px / 3D m; use
|
|
1036
|
+
* [x, y] or [x, y, z] to match the node). Emits `waypointReached(index)`
|
|
1037
|
+
* per point and `arrived()` at the end. `loop: true` patrols the ring.
|
|
1038
|
+
*/
|
|
1039
|
+
var PathFollow = class extends Behavior {
|
|
1040
|
+
static signals = ["waypointReached", "arrived"];
|
|
1041
|
+
static props = {
|
|
1042
|
+
speed: { default: 120 },
|
|
1043
|
+
loop: { default: false }
|
|
1044
|
+
};
|
|
1045
|
+
/** Units per second (px in 2D, meters in 3D). */
|
|
1046
|
+
speed = 120;
|
|
1047
|
+
loop = false;
|
|
1048
|
+
waypoints = [];
|
|
1049
|
+
index = 0;
|
|
1050
|
+
/** True while there is somewhere left to go. */
|
|
1051
|
+
get moving() {
|
|
1052
|
+
return this.index < this.waypoints.length;
|
|
1053
|
+
}
|
|
1054
|
+
setPath(waypoints) {
|
|
1055
|
+
this.waypoints = waypoints.map((w) => [...w]);
|
|
1056
|
+
this.index = 0;
|
|
1057
|
+
}
|
|
1058
|
+
/** Stop in place (keeps the node where it is). */
|
|
1059
|
+
stop() {
|
|
1060
|
+
this.waypoints = [];
|
|
1061
|
+
this.index = 0;
|
|
1062
|
+
}
|
|
1063
|
+
update(dt) {
|
|
1064
|
+
if (!this.moving) return;
|
|
1065
|
+
const node = requirePosition(this);
|
|
1066
|
+
let budget = this.speed * dt;
|
|
1067
|
+
while (budget > 0 && this.index < this.waypoints.length) {
|
|
1068
|
+
const target = this.waypoints[this.index];
|
|
1069
|
+
const step = moveToward(node.position, target, budget);
|
|
1070
|
+
const travelled = distanceBetween(node.position, step.position);
|
|
1071
|
+
node.position = step.position;
|
|
1072
|
+
budget -= travelled;
|
|
1073
|
+
if (step.reached) {
|
|
1074
|
+
this.node.emit("waypointReached", this.index);
|
|
1075
|
+
this.index += 1;
|
|
1076
|
+
if (this.index >= this.waypoints.length) if (this.loop && this.waypoints.length > 1) this.index = 0;
|
|
1077
|
+
else {
|
|
1078
|
+
this.node.emit("arrived");
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
} else return;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
function distanceBetween(a, b) {
|
|
1086
|
+
let sum = 0;
|
|
1087
|
+
const n = Math.max(a.length, b.length);
|
|
1088
|
+
for (let i = 0; i < n; i++) {
|
|
1089
|
+
const d = (b[i] ?? 0) - (a[i] ?? 0);
|
|
1090
|
+
sum += d * d;
|
|
1091
|
+
}
|
|
1092
|
+
return Math.sqrt(sum);
|
|
1093
|
+
}
|
|
1094
|
+
//#endregion
|
|
989
1095
|
//#region src/gameplay/patrol.ts
|
|
990
1096
|
/**
|
|
991
1097
|
* Walk the node along a fixed list of waypoints at constant speed — guards,
|
|
@@ -1739,6 +1845,7 @@ var ZombieAI = class extends Behavior {
|
|
|
1739
1845
|
const GAMEPLAY_BEHAVIORS = {
|
|
1740
1846
|
CameraShake,
|
|
1741
1847
|
GameFlow,
|
|
1848
|
+
PathFollow,
|
|
1742
1849
|
Health,
|
|
1743
1850
|
Lifetime,
|
|
1744
1851
|
ScoreKeeper,
|
|
@@ -1767,4 +1874,4 @@ function registerGameplayBehaviors(opts) {
|
|
|
1767
1874
|
for (const [name, ctor] of Object.entries(GAMEPLAY_BEHAVIORS)) registerBehavior(name, ctor, { replace });
|
|
1768
1875
|
}
|
|
1769
1876
|
//#endregion
|
|
1770
|
-
export {
|
|
1877
|
+
export { FollowCamera as C, Chase as D, Collector as E, restartScene as S, Health as T, hitStop as _, Wander as a, GameFlow as b, Projectile as c, PathFollow as d, Oscillate as f, Cooldown as g, CameraShake as h, WaveSpawner as i, Pickup as l, Lifetime as m, registerGameplayBehaviors as n, Spawner as o, MoveTo as p, ZombieAI as r, ScoreKeeper as s, GAMEPLAY_BEHAVIORS as t, Patrol as u, screenFlash as v, DamageOnContact as w, goToScene as x, Interactable as y };
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as JsonValue } from "./schema-CcoWb32N.js";
|
|
2
|
-
import {
|
|
1
|
+
import { c as JsonValue, s as JsonObject } from "./schema-CcoWb32N.js";
|
|
2
|
+
import { $ as Node, l as PropSchema, n as BehaviorCtor, t as Behavior, v as Engine } from "./behavior-Bod1AyJS.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
5
5
|
/**
|
|
@@ -541,6 +541,13 @@ declare class ZombieAI extends Behavior {
|
|
|
541
541
|
declare function restartScene(engine: Engine): void;
|
|
542
542
|
type GameFlowState = "playing" | "paused" | "gameover" | "won";
|
|
543
543
|
/**
|
|
544
|
+
* Swap to another scene behind a black fade (title→game→next level).
|
|
545
|
+
* Headless (no DOM) the swap is immediate. Restores timeScale to 1.
|
|
546
|
+
*/
|
|
547
|
+
declare function goToScene(engine: Engine, sceneJson: JsonObject, opts?: {
|
|
548
|
+
fadeSeconds?: number;
|
|
549
|
+
}): void;
|
|
550
|
+
/**
|
|
544
551
|
* The win/lose/restart state machine 6+ examples hand-rolled as `over`/`win`
|
|
545
552
|
* booleans. Attach to any node (the scene root is natural):
|
|
546
553
|
*
|
|
@@ -573,6 +580,10 @@ declare class GameFlow extends Behavior {
|
|
|
573
580
|
pause(): void;
|
|
574
581
|
resume(): void;
|
|
575
582
|
restart(): void;
|
|
583
|
+
/** Fade to another scene (next level, back to title). */
|
|
584
|
+
goToScene(sceneJson: JsonObject, opts?: {
|
|
585
|
+
fadeSeconds?: number;
|
|
586
|
+
}): void;
|
|
576
587
|
private transition;
|
|
577
588
|
private freeze;
|
|
578
589
|
private thaw;
|
|
@@ -639,6 +650,36 @@ declare function screenFlash(color?: string, opacity?: number, seconds?: number)
|
|
|
639
650
|
*/
|
|
640
651
|
declare function hitStop(engine: Engine, seconds?: number): void;
|
|
641
652
|
//#endregion
|
|
653
|
+
//#region src/gameplay/path-follow.d.ts
|
|
654
|
+
/**
|
|
655
|
+
* Walk a list of waypoints at a constant speed, then stop — the delivery
|
|
656
|
+
* end of `findPath`:
|
|
657
|
+
*
|
|
658
|
+
* const cells = findPath(grid, start, goal);
|
|
659
|
+
* (npc.behavior as PathFollow).setPath(cells.map(([cx, cy]) => [cx * TILE, cy * TILE]));
|
|
660
|
+
*
|
|
661
|
+
* Waypoints are world positions in the node's own units (2D px / 3D m; use
|
|
662
|
+
* [x, y] or [x, y, z] to match the node). Emits `waypointReached(index)`
|
|
663
|
+
* per point and `arrived()` at the end. `loop: true` patrols the ring.
|
|
664
|
+
*/
|
|
665
|
+
declare class PathFollow extends Behavior {
|
|
666
|
+
static readonly signals: readonly string[];
|
|
667
|
+
static readonly props: Record<string, {
|
|
668
|
+
default: number | boolean;
|
|
669
|
+
}>;
|
|
670
|
+
/** Units per second (px in 2D, meters in 3D). */
|
|
671
|
+
speed: number;
|
|
672
|
+
loop: boolean;
|
|
673
|
+
private waypoints;
|
|
674
|
+
private index;
|
|
675
|
+
/** True while there is somewhere left to go. */
|
|
676
|
+
get moving(): boolean;
|
|
677
|
+
setPath(waypoints: readonly (readonly number[])[]): void;
|
|
678
|
+
/** Stop in place (keeps the node where it is). */
|
|
679
|
+
stop(): void;
|
|
680
|
+
override update(dt: number): void;
|
|
681
|
+
}
|
|
682
|
+
//#endregion
|
|
642
683
|
//#region src/gameplay/index.d.ts
|
|
643
684
|
/** Every built-in gameplay behavior, keyed by its registration name. */
|
|
644
685
|
declare const GAMEPLAY_BEHAVIORS: Readonly<Record<string, BehaviorCtor>>;
|
|
@@ -651,4 +692,4 @@ declare function registerGameplayBehaviors(opts?: {
|
|
|
651
692
|
replace?: boolean;
|
|
652
693
|
}): void;
|
|
653
694
|
//#endregion
|
|
654
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, type GameFlowState, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, hitStop, registerGameplayBehaviors, restartScene, screenFlash };
|
|
695
|
+
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, type GameFlowState, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, hitStop, registerGameplayBehaviors, restartScene, screenFlash };
|
|
1
|
+
import { C as FollowCamera, D as Chase, E as Collector, S as restartScene, T as Health, _ as hitStop, a as Wander, b as GameFlow, c as Projectile, d as PathFollow, f as Oscillate, g as Cooldown, h as CameraShake, i as WaveSpawner, l as Pickup, m as Lifetime, n as registerGameplayBehaviors, o as Spawner, p as MoveTo, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as screenFlash, w as DamageOnContact, x as goToScene, y as Interactable } from "./gameplay-DPMgZk9W.js";
|
|
2
|
+
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as Rng, c as JsonValue, d as jsonKind, i as SceneJson, l as jsonClone, n as NodeJson, o as JsonKind, r as SCENE_FORMAT, s as JsonObject, t as ConnectionJson, u as jsonEquals } from "./schema-CcoWb32N.js";
|
|
2
|
-
import { $ as
|
|
3
|
-
import { n as loadScene, t as LoadSceneOptions } from "./loader-
|
|
2
|
+
import { $ as Node, A as SfxPlayOptions, B as spatialPan, C as RendererStats, D as LogManager, E as LogLevel, F as ROLLOFF_MODELS, G as SynthOptions, H as SFX_PRESET_NAMES, I as RolloffModel, J as MusicManager, K as synthSfx, L as SpatialParams, M as Voice, N as VoicePreset, O as InputMap, P as Listener, Q as BusName, R as Vec3, S as GameStats, T as LogEntry, U as SfxParams, V as SFX_PRESETS, W as SfxWave, X as PlayMusicOptions, Y as MusicTrack, Z as AudioBuses, _ as registeredTypes, a as registerBehavior, b as Scheduler, c as PropDef, d as createNode, et as NodeLifecycle, f as getNodeSchema, g as registerNode, h as mergeStaticSignals, i as getBehavior, j as isAudioContextAvailable, k as SfxEngine, l as PropSchema, m as getNodeType, n as BehaviorCtor, nt as SignalListener, o as registeredBehaviors, p as getNodeSignals, q as MusicBackend, r as clearBehaviors, rt as SceneTree, s as NodeCtor, t as Behavior, tt as Signal, u as clearRegistry, v as Engine, w as Scene, x as EngineStats, y as EngineOptions, z as spatialGain } from "./behavior-Bod1AyJS.js";
|
|
3
|
+
import { n as loadScene, t as LoadSceneOptions } from "./loader-BcUDfNHn.js";
|
|
4
4
|
import { n as ParticleSimConfig, r as ParticleView, t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
|
|
5
|
-
import { n as AudioPlayer, t as AudioElementLike } from "./audio-player-
|
|
6
|
-
import { n as IncantoErrorCode, r as IncantoErrorDetails, t as IncantoError } from "./errors-
|
|
5
|
+
import { n as AudioPlayer, t as AudioElementLike } from "./audio-player-Dyjg5k92.js";
|
|
6
|
+
import { i as auditScene, n as IncantoErrorCode, r as IncantoErrorDetails, t as IncantoError } from "./errors-1dXlIwoR.js";
|
|
7
7
|
|
|
8
8
|
//#region src/core/audio/crossfade.d.ts
|
|
9
9
|
/**
|
|
@@ -114,7 +114,7 @@ declare class HudLayer extends Node {
|
|
|
114
114
|
_slot(anchor: HudAnchor): HTMLElement | null;
|
|
115
115
|
}
|
|
116
116
|
/** Shared plumbing: mount into the parent HudLayer's anchor slot. */
|
|
117
|
-
declare abstract class
|
|
117
|
+
declare abstract class HudWidgetBase extends Node {
|
|
118
118
|
static readonly props: PropSchema;
|
|
119
119
|
anchor: HudAnchor;
|
|
120
120
|
visible: boolean;
|
|
@@ -128,7 +128,7 @@ declare abstract class HudWidget extends Node {
|
|
|
128
128
|
protected _sync(): void;
|
|
129
129
|
}
|
|
130
130
|
/** A text line (score, timer, hints). Set `.text` from behaviors. */
|
|
131
|
-
declare class UiText extends
|
|
131
|
+
declare class UiText extends HudWidgetBase {
|
|
132
132
|
static override readonly typeName: string;
|
|
133
133
|
static override readonly props: PropSchema;
|
|
134
134
|
text: string;
|
|
@@ -140,7 +140,7 @@ declare class UiText extends HudWidget {
|
|
|
140
140
|
protected override _sync(): void;
|
|
141
141
|
}
|
|
142
142
|
/** A labeled progress bar (health, stamina, reload, boss HP). */
|
|
143
|
-
declare class UiBar extends
|
|
143
|
+
declare class UiBar extends HudWidgetBase {
|
|
144
144
|
static override readonly typeName: string;
|
|
145
145
|
static override readonly props: PropSchema;
|
|
146
146
|
value: number;
|
|
@@ -164,7 +164,7 @@ declare class UiBar extends HudWidget {
|
|
|
164
164
|
* in/out and a queue — call `.show(text, { color, seconds })`; `sticky:true`
|
|
165
165
|
* (seconds: 0) keeps it until the next show(). Emits `bannerShown(text)`.
|
|
166
166
|
*/
|
|
167
|
-
declare class UiBanner extends
|
|
167
|
+
declare class UiBanner extends HudWidgetBase {
|
|
168
168
|
static override readonly typeName: string;
|
|
169
169
|
static readonly signals: string[];
|
|
170
170
|
static override readonly props: PropSchema;
|
|
@@ -187,6 +187,75 @@ declare class UiBanner extends HudWidget {
|
|
|
187
187
|
override update(dt: number): void;
|
|
188
188
|
}
|
|
189
189
|
//#endregion
|
|
190
|
+
//#region src/core/nodes/dialogue.d.ts
|
|
191
|
+
/**
|
|
192
|
+
* Interactive HUD: clickable buttons and a typewriter dialogue box — the
|
|
193
|
+
* storytelling layer RPG/adventure games kept hand-rolling in DOM.
|
|
194
|
+
* Same family as the other HUD widgets: children of a HudLayer, DOM-backed,
|
|
195
|
+
* silent no-ops headless.
|
|
196
|
+
*/
|
|
197
|
+
/** A clickable button (menus, "START", dialog choices). Emits `pressed`. */
|
|
198
|
+
declare class UiButton extends HudWidgetBase {
|
|
199
|
+
static override readonly typeName: string;
|
|
200
|
+
static readonly signals: readonly string[];
|
|
201
|
+
static override readonly props: PropSchema;
|
|
202
|
+
text: string;
|
|
203
|
+
size: number;
|
|
204
|
+
color: string;
|
|
205
|
+
background: string;
|
|
206
|
+
disabled: boolean;
|
|
207
|
+
private lastText;
|
|
208
|
+
/** Programmatic press — same path as a click (tests, gamepad menus). */
|
|
209
|
+
press(): void;
|
|
210
|
+
protected _build(): HTMLElement;
|
|
211
|
+
protected override _sync(): void;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A typewriter dialogue box with a queue and choices:
|
|
215
|
+
*
|
|
216
|
+
* const talk = node.getNode('%Dialogue') as UiDialogue;
|
|
217
|
+
* talk.say('Elder', 'Welcome to Lumina Village...');
|
|
218
|
+
* talk.say('Elder', 'Will you help us?', ['Yes', 'No']);
|
|
219
|
+
* talk.on('choiceMade', (index) => { ... });
|
|
220
|
+
*
|
|
221
|
+
* Click / `advance()` reveals the full line, then advances. Emits
|
|
222
|
+
* `lineShown(text)`, `choiceMade(index)`, `dialogueFinished()`.
|
|
223
|
+
*/
|
|
224
|
+
declare class UiDialogue extends HudWidgetBase {
|
|
225
|
+
static override readonly typeName: string;
|
|
226
|
+
static readonly signals: readonly string[];
|
|
227
|
+
static override readonly props: PropSchema;
|
|
228
|
+
override anchor: HudAnchor;
|
|
229
|
+
/** Typewriter speed; 0 = instant lines. */
|
|
230
|
+
charsPerSecond: number;
|
|
231
|
+
width: number;
|
|
232
|
+
private queue;
|
|
233
|
+
private current;
|
|
234
|
+
private revealed;
|
|
235
|
+
private speakerEl;
|
|
236
|
+
private textEl;
|
|
237
|
+
private choicesEl;
|
|
238
|
+
private hintEl;
|
|
239
|
+
/** True while a conversation is on screen (pause player input on this). */
|
|
240
|
+
get active(): boolean;
|
|
241
|
+
/** What the box currently shows (grows while typing) — test-friendly. */
|
|
242
|
+
get showing(): string;
|
|
243
|
+
/** Queue a line; optional `choices` renders buttons after the line types out. */
|
|
244
|
+
say(speaker: string, text: string, choices?: string[]): void;
|
|
245
|
+
/**
|
|
246
|
+
* Player pressed "next": mid-typing reveals the whole line; a fully-typed
|
|
247
|
+
* line without choices advances (choice lines wait for `choose`).
|
|
248
|
+
*/
|
|
249
|
+
advance(): void;
|
|
250
|
+
/** Pick a choice on the current line (buttons call this). */
|
|
251
|
+
choose(index: number): void;
|
|
252
|
+
/** Drop the conversation (cutscene interrupts). */
|
|
253
|
+
clear(): void;
|
|
254
|
+
private next;
|
|
255
|
+
protected _build(): HTMLElement;
|
|
256
|
+
override update(dt: number): void;
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
190
259
|
//#region src/core/nodes/timer.d.ts
|
|
191
260
|
/**
|
|
192
261
|
* The canonical serializable game clock — never `setTimeout` in game logic.
|
|
@@ -267,6 +336,33 @@ declare const PARTICLE_PRESET_NAMES: readonly string[];
|
|
|
267
336
|
*/
|
|
268
337
|
declare function applyParticlePreset(target: Record<string, unknown>, presetName: string, schema: PropSchema): void;
|
|
269
338
|
//#endregion
|
|
339
|
+
//#region src/core/pathfinding.d.ts
|
|
340
|
+
/**
|
|
341
|
+
* Grid A* — the pathfinding every top-down/RPG/tower-defense asks for and
|
|
342
|
+
* agents keep re-inventing badly. Pure and dimension-free: cells in, cells
|
|
343
|
+
* out; the caller maps cells to world units (px, meters, tiles).
|
|
344
|
+
*/
|
|
345
|
+
interface PathGrid {
|
|
346
|
+
width: number;
|
|
347
|
+
height: number;
|
|
348
|
+
/** True = impassable. Out-of-bounds is always solid. */
|
|
349
|
+
solid(x: number, y: number): boolean;
|
|
350
|
+
}
|
|
351
|
+
interface FindPathOptions {
|
|
352
|
+
/** Allow diagonal steps (blocked from cutting corners). Default true. */
|
|
353
|
+
diagonal?: boolean;
|
|
354
|
+
/** Abort guard for huge/impossible searches. Default 20000 nodes. */
|
|
355
|
+
maxExpansions?: number;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* A* from `from` to `to` (inclusive cell coords). Returns the cell path
|
|
359
|
+
* INCLUDING both endpoints, or null when unreachable. Straight steps cost
|
|
360
|
+
* 1, diagonals √2; the heuristic is octile (admissible for both modes).
|
|
361
|
+
*/
|
|
362
|
+
declare function findPath(grid: PathGrid, from: [number, number], to: [number, number], opts?: FindPathOptions): [number, number][] | null;
|
|
363
|
+
/** Build a PathGrid from row-strings ('#' = solid) — tests and tile games. */
|
|
364
|
+
declare function gridFromRows(rows: readonly string[]): PathGrid;
|
|
365
|
+
//#endregion
|
|
270
366
|
//#region src/core/preload.d.ts
|
|
271
367
|
interface PreloadResult {
|
|
272
368
|
/** Urls whose fetch failed — show an error UI instead of pretending success. */
|
|
@@ -310,6 +406,52 @@ declare function resolveRendering(environment: JsonObject | undefined, fallback:
|
|
|
310
406
|
pixelRatio?: number;
|
|
311
407
|
}): ResolvedRendering;
|
|
312
408
|
//#endregion
|
|
409
|
+
//#region src/core/replay.d.ts
|
|
410
|
+
/**
|
|
411
|
+
* Deterministic input replay — the engine already runs on a seeded RNG and
|
|
412
|
+
* an injectable clock, so a recording of (tick timestamps + input events)
|
|
413
|
+
* replays BIT-IDENTICALLY into a fresh engine with the same seed and scene.
|
|
414
|
+
* That turns "does my game still work?" into an assertion an agent can run
|
|
415
|
+
* headlessly: record once while playing, replay forever as a regression.
|
|
416
|
+
*
|
|
417
|
+
* const rec = startRecording(engine); // play the game...
|
|
418
|
+
* const replayJson = rec.stop(); // ...save this JSON
|
|
419
|
+
*
|
|
420
|
+
* const fresh = new Engine({ seed: SAME_SEED }); // same seed + scene JSON
|
|
421
|
+
* fresh.setScene(loadScene(sceneJson));
|
|
422
|
+
* replay(fresh, replayJson); // now assert game state
|
|
423
|
+
*
|
|
424
|
+
* Caveats (documented, by design): game code must use `engine.rng` (not
|
|
425
|
+
* Math.random) and dt/engine.time (not Date.now) — the engine's own rules.
|
|
426
|
+
* Gamepad polling is not recorded (bind pads to actions; actions replay).
|
|
427
|
+
*/
|
|
428
|
+
/** [tickIndex, methodName, ...primitive args] */
|
|
429
|
+
type ReplayEvent = [number, string, ...(string | number | boolean)[]];
|
|
430
|
+
interface ReplayJson {
|
|
431
|
+
/** File-format marker for forward compatibility. */
|
|
432
|
+
replay: 1;
|
|
433
|
+
/** Tick timestamps (ms) exactly as the loop delivered them. */
|
|
434
|
+
ticks: number[];
|
|
435
|
+
events: ReplayEvent[];
|
|
436
|
+
}
|
|
437
|
+
interface Recorder {
|
|
438
|
+
/** Detach the taps and return the recording. */
|
|
439
|
+
stop(): ReplayJson;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Tap the engine's input entry points and tick clock. Recording starts at
|
|
443
|
+
* the CURRENT moment — start it before the first tick for full-run replays.
|
|
444
|
+
*/
|
|
445
|
+
declare function startRecording(engine: Engine): Recorder;
|
|
446
|
+
/**
|
|
447
|
+
* Drive a fresh engine through a recording: for each recorded tick, feed
|
|
448
|
+
* that tick's input events first, then tick with the recorded timestamp.
|
|
449
|
+
* `onTick(index)` lets tests assert mid-run state.
|
|
450
|
+
*/
|
|
451
|
+
declare function replay(engine: Engine, recording: ReplayJson, opts?: {
|
|
452
|
+
onTick?: (index: number) => void;
|
|
453
|
+
}): void;
|
|
454
|
+
//#endregion
|
|
313
455
|
//#region src/core/save.d.ts
|
|
314
456
|
/**
|
|
315
457
|
* Namespaced game persistence — high scores, unlocks, settings. localStorage
|
|
@@ -453,4 +595,4 @@ declare function computeViewport(canvasW: number, canvasH: number, viewport: {
|
|
|
453
595
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
454
596
|
declare const VERSION: string;
|
|
455
597
|
//#endregion
|
|
456
|
-
export { AudioBuses, type AudioElementLike, AudioPlayer, Behavior, type BehaviorCtor, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, Engine, type EngineOptions, type EngineStats, type GameStats, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LoadSceneOptions, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, ROLLOFF_MODELS, type RendererStats, type ResolvedRendering, type ResolvedViewport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiText, VERSION, type Vec3, type ViewportFit, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, getBehavior, getNodeSchema, getNodeSignals, getNodeType, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, synthSfx };
|
|
598
|
+
export { AudioBuses, type AudioElementLike, AudioPlayer, Behavior, type BehaviorCtor, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, Engine, type EngineOptions, type EngineStats, type FindPathOptions, type GameStats, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LoadSceneOptions, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PathGrid, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, ROLLOFF_MODELS, type Recorder, type RendererStats, type ReplayEvent, type ReplayJson, type ResolvedRendering, type ResolvedViewport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiButton, UiDialogue, UiText, VERSION, type Vec3, type ViewportFit, type Voice, type VoicePreset, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, startRecording, synthSfx };
|