incanto 0.41.0 → 0.43.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-feel.mjs +20 -1
- package/bin/incanto-frame.mjs +144 -0
- package/dist/2d.d.ts +2 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +76 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-TA8nySqb.d.ts → behavior-62q0HWBO.d.ts} +3 -1
- package/dist/{create-game-u7TDbvln.js → create-game-B3vBWgVD.js} +160 -6
- package/dist/{create-game-CZpENyin.js → create-game-DFRbG0Bj.js} +6 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{environment-presets-pGTHb_V4.js → environment-presets-Ds5kXLoF.js} +2 -2
- package/dist/{gameplay-By8mslMc.js → gameplay-BQOeAid6.js} +50 -0
- package/dist/gameplay.d.ts +30 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -167
- package/dist/{loader-CvSDKC3v.d.ts → loader-CeyU_bm1.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-_UlKUoox.d.ts → pathfinding-C49JSNNq.d.ts} +1 -1
- package/dist/{physics-2d-CEnZFcpM.js → physics-2d-BmgXBNDB.js} +1 -1
- package/dist/{physics-3d-CumBBvQo.js → physics-3d-CLPFv99o.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-DuTlY56W.js → register-BSXV8T9F.js} +3 -1
- package/dist/{register-DnycZ91Q.js → register-D651it1J.js} +1 -1
- package/dist/{register-MSZvnHkp.js → register-R2JTnIMw.js} +1 -1
- package/dist/{replay-DN-kG4va.d.ts → replay-CAphXMyM.d.ts} +1 -1
- package/dist/{replay-DcWg4LT5.js → replay-DilbZgQI.js} +1 -1
- package/dist/src-CwYxzZKl.js +166 -0
- package/dist/{teardown-CCtAMDLB.js → teardown-yePMOE1K.js} +32 -1
- package/dist/{test-B4kSwQzq.js → test-BMgiiD5i.js} +135 -12
- package/dist/test.d.ts +38 -4
- package/dist/test.js +3 -3
- package/dist/vite.d.ts +61 -1
- package/dist/vite.js +149 -2
- package/editor/assets/{agent8-DCHkff44.js → agent8-Cl3qFuBB.js} +1 -1
- package/editor/assets/{debug-uHHxqj0a.js → debug-u3yLCciO.js} +1 -1
- package/editor/assets/{index-i1mIkyMA.js → index-Dk2ZlO68.js} +60 -60
- package/editor/index.html +1 -1
- package/package.json +3 -2
- package/skills/incanto-3d-character.md +19 -0
- package/skills/incanto-audio.md +6 -2
- package/skills/incanto-gameplay-behaviors.md +27 -0
- package/skills/incanto-node-reference.md +2 -0
- package/skills/incanto-verifying-your-game.md +41 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +47 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +53 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +43 -0
|
@@ -4973,10 +4973,15 @@ var GameFlow = class extends Behavior {
|
|
|
4973
4973
|
static signals = ["flowChanged"];
|
|
4974
4974
|
static props = {
|
|
4975
4975
|
restartAction: { default: "restart" },
|
|
4976
|
+
pauseAction: { default: "pause" },
|
|
4976
4977
|
freezeOnEnd: { default: true },
|
|
4977
4978
|
bannerPath: {
|
|
4978
4979
|
default: "%Banner",
|
|
4979
4980
|
nodePath: true
|
|
4981
|
+
},
|
|
4982
|
+
pausePanelPath: {
|
|
4983
|
+
default: "%PauseMenu",
|
|
4984
|
+
nodePath: true
|
|
4980
4985
|
}
|
|
4981
4986
|
};
|
|
4982
4987
|
/** Input action that restarts from gameover/won (declare it in `input{}`). */
|
|
@@ -4985,8 +4990,31 @@ var GameFlow = class extends Behavior {
|
|
|
4985
4990
|
freezeOnEnd = true;
|
|
4986
4991
|
/** Where the flow looks for a UiBanner ('' = never). */
|
|
4987
4992
|
bannerPath = "%Banner";
|
|
4993
|
+
/**
|
|
4994
|
+
* Input action that toggles pause (declare it in `input{}`; undeclared is
|
|
4995
|
+
* fine and means pause is API-only).
|
|
4996
|
+
*/
|
|
4997
|
+
pauseAction = "pause";
|
|
4998
|
+
/**
|
|
4999
|
+
* A node shown while paused and hidden otherwise — a `UiPanel` of buttons in
|
|
5000
|
+
* practice. '' turns the whole thing off.
|
|
5001
|
+
*
|
|
5002
|
+
* This lives here rather than in each game because it is identical in all of
|
|
5003
|
+
* them, and a pause menu that costs a script is a pause menu no generated
|
|
5004
|
+
* game will have. `UiPanel` appeared in zero template scenes before this.
|
|
5005
|
+
*/
|
|
5006
|
+
pausePanelPath = "%PauseMenu";
|
|
4988
5007
|
state = "playing";
|
|
4989
5008
|
frozeScale = false;
|
|
5009
|
+
onReady() {
|
|
5010
|
+
this.syncPausePanel();
|
|
5011
|
+
}
|
|
5012
|
+
/** The panel follows the state; nothing else may own its visibility. */
|
|
5013
|
+
syncPausePanel() {
|
|
5014
|
+
if (this.pausePanelPath === "") return;
|
|
5015
|
+
const panel = this.node.getNodeOrNull(this.pausePanelPath);
|
|
5016
|
+
if (panel && "visible" in panel) panel.visible = this.state === "paused";
|
|
5017
|
+
}
|
|
4990
5018
|
gameOver(text = "GAME OVER", color = "#ef4444") {
|
|
4991
5019
|
this.transition("gameover", text, color);
|
|
4992
5020
|
}
|
|
@@ -4997,12 +5025,14 @@ var GameFlow = class extends Behavior {
|
|
|
4997
5025
|
if (this.state !== "playing") return;
|
|
4998
5026
|
this.state = "paused";
|
|
4999
5027
|
this.freeze();
|
|
5028
|
+
this.syncPausePanel();
|
|
5000
5029
|
this.node.emit("flowChanged", this.state);
|
|
5001
5030
|
}
|
|
5002
5031
|
resume() {
|
|
5003
5032
|
if (this.state !== "paused") return;
|
|
5004
5033
|
this.state = "playing";
|
|
5005
5034
|
this.thaw();
|
|
5035
|
+
this.syncPausePanel();
|
|
5006
5036
|
this.node.emit("flowChanged", this.state);
|
|
5007
5037
|
}
|
|
5008
5038
|
restart() {
|
|
@@ -5035,6 +5065,13 @@ var GameFlow = class extends Behavior {
|
|
|
5035
5065
|
this.engine.timeScale = 1;
|
|
5036
5066
|
}
|
|
5037
5067
|
update() {
|
|
5068
|
+
if (this.state === "playing" || this.state === "paused") {
|
|
5069
|
+
try {
|
|
5070
|
+
if (this.engine.input.justPressed(this.pauseAction)) if (this.state === "playing") this.pause();
|
|
5071
|
+
else this.resume();
|
|
5072
|
+
} catch {}
|
|
5073
|
+
return;
|
|
5074
|
+
}
|
|
5038
5075
|
if (this.state !== "gameover" && this.state !== "won") return;
|
|
5039
5076
|
try {
|
|
5040
5077
|
if (this.engine.input.justPressed(this.restartAction)) this.restart();
|
|
@@ -5166,7 +5203,20 @@ var CameraShake = class extends Behavior {
|
|
|
5166
5203
|
magnitude = 0;
|
|
5167
5204
|
t = 0;
|
|
5168
5205
|
prev = [];
|
|
5206
|
+
/**
|
|
5207
|
+
* Start a shake — unless the player asked for no motion.
|
|
5208
|
+
*
|
|
5209
|
+
* `settings.reduceMotion` is an accessibility switch, and camera movement the
|
|
5210
|
+
* player did not cause is the vestibular trigger it exists for. Checked HERE
|
|
5211
|
+
* rather than in `update` so a shake requested while it is on leaves nothing
|
|
5212
|
+
* queued to play the moment it is turned off.
|
|
5213
|
+
*
|
|
5214
|
+
* It deliberately does NOT touch gameplay timing (`hitStop`): freezing time
|
|
5215
|
+
* for 80 ms is feedback, not motion, and removing it would change what the
|
|
5216
|
+
* game is rather than how it moves.
|
|
5217
|
+
*/
|
|
5169
5218
|
shake(magnitude, seconds) {
|
|
5219
|
+
if (this.engine?.settings.get("reduceMotion") === true) return;
|
|
5170
5220
|
this.magnitude = Math.max(this.magnitude, magnitude);
|
|
5171
5221
|
this.t = seconds ?? this.falloff;
|
|
5172
5222
|
}
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Et as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { Et as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-62q0HWBO.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
@@ -622,8 +622,25 @@ declare class GameFlow extends Behavior {
|
|
|
622
622
|
freezeOnEnd: boolean;
|
|
623
623
|
/** Where the flow looks for a UiBanner ('' = never). */
|
|
624
624
|
bannerPath: string;
|
|
625
|
+
/**
|
|
626
|
+
* Input action that toggles pause (declare it in `input{}`; undeclared is
|
|
627
|
+
* fine and means pause is API-only).
|
|
628
|
+
*/
|
|
629
|
+
pauseAction: string;
|
|
630
|
+
/**
|
|
631
|
+
* A node shown while paused and hidden otherwise — a `UiPanel` of buttons in
|
|
632
|
+
* practice. '' turns the whole thing off.
|
|
633
|
+
*
|
|
634
|
+
* This lives here rather than in each game because it is identical in all of
|
|
635
|
+
* them, and a pause menu that costs a script is a pause menu no generated
|
|
636
|
+
* game will have. `UiPanel` appeared in zero template scenes before this.
|
|
637
|
+
*/
|
|
638
|
+
pausePanelPath: string;
|
|
625
639
|
state: GameFlowState;
|
|
626
640
|
private frozeScale;
|
|
641
|
+
override onReady(): void;
|
|
642
|
+
/** The panel follows the state; nothing else may own its visibility. */
|
|
643
|
+
private syncPausePanel;
|
|
627
644
|
gameOver(text?: string, color?: string): void;
|
|
628
645
|
win(text?: string, color?: string): void;
|
|
629
646
|
pause(): void;
|
|
@@ -685,6 +702,18 @@ declare class CameraShake extends Behavior {
|
|
|
685
702
|
private magnitude;
|
|
686
703
|
private t;
|
|
687
704
|
private prev;
|
|
705
|
+
/**
|
|
706
|
+
* Start a shake — unless the player asked for no motion.
|
|
707
|
+
*
|
|
708
|
+
* `settings.reduceMotion` is an accessibility switch, and camera movement the
|
|
709
|
+
* player did not cause is the vestibular trigger it exists for. Checked HERE
|
|
710
|
+
* rather than in `update` so a shake requested while it is on leaves nothing
|
|
711
|
+
* queued to play the moment it is turned off.
|
|
712
|
+
*
|
|
713
|
+
* It deliberately does NOT touch gameplay timing (`hitStop`): freezing time
|
|
714
|
+
* for 80 ms is feedback, not motion, and removing it would change what the
|
|
715
|
+
* game is rather than how it moves.
|
|
716
|
+
*/
|
|
688
717
|
shake(magnitude: number, seconds?: number): void;
|
|
689
718
|
override update(dt: number): void;
|
|
690
719
|
}
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ 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, k as Chase, 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 DayNight, x as goToScene, y as Interactable } from "./gameplay-
|
|
1
|
+
import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ 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, k as Chase, 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 DayNight, x as goToScene, y as Interactable } from "./gameplay-BQOeAid6.js";
|
|
2
2
|
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { $ as suggestLocale, A as SettingsValues, At as LogLevel, B as captureBehaviors, C as EngineStats, Ct as PlayMusicOptions, Dt as NodeLifecycle, E as DeviceHints, Et as Node, F as BehaviorState, G as OrderGroup, H as SaveStore, I as RestoreReport, J as resolveOrderGroups, K as OrderGroupTable, L as SaveSlot, M as readDeviceHints, Mt as Signal, N as suggestQuality, Nt as SignalListener, O as QualityTier, Ot as SceneTree, P as Scene, Q as T_PREFIX, R as SaveSlots, S as Scheduler, St as MusicTrack, T as RendererStats, Tt as BusName, U as createSaveStore, V as restoreBehaviors, W as ORDER_GROUP_BASE, X as LocaleTables, Y as BASE_LOCALE, Z as Localization, _ as mergeStaticSignals, _t as SfxWave, a as clearBehaviors, at as Voice, b as Engine, bt as MusicBackend, c as registeredBehaviors, ct as ROLLOFF_MODELS, d as PropSchema, dt as Vec3, et as translationKey, f as clearRegistry, ft as spatialGain, g as getNodeType, gt as SfxParams, h as getNodeSignals, ht as SFX_PRESET_NAMES, i as behaviorSignals, it as isAudioContextAvailable, j as qualityEnvironment, jt as LogManager, k as Settings, kt as LogEntry, l as NodeCtor, lt as RolloffModel, m as getNodeSchema, mt as SFX_PRESETS, n as BehaviorCtor, nt as SfxEngine, o as getBehavior, ot as VoicePreset, p as createNode, pt as spatialPan, q as effectiveOrder, r as behaviorSchema, rt as SfxPlayOptions, s as registerBehavior, st as Listener, t as Behavior, tt as InputMap, u as PropDef, ut as SpatialParams, v as registerNode, vt as SynthOptions, w as GameStats, wt as AudioBuses, x as EngineOptions, xt as MusicManager, y as registeredTypes, yt as synthSfx, z as behaviorsWithoutSave } from "./behavior-
|
|
1
|
+
import { $ as suggestLocale, A as SettingsValues, At as LogLevel, B as captureBehaviors, C as EngineStats, Ct as PlayMusicOptions, Dt as NodeLifecycle, E as DeviceHints, Et as Node, F as BehaviorState, G as OrderGroup, H as SaveStore, I as RestoreReport, J as resolveOrderGroups, K as OrderGroupTable, L as SaveSlot, M as readDeviceHints, Mt as Signal, N as suggestQuality, Nt as SignalListener, O as QualityTier, Ot as SceneTree, P as Scene, Q as T_PREFIX, R as SaveSlots, S as Scheduler, St as MusicTrack, T as RendererStats, Tt as BusName, U as createSaveStore, V as restoreBehaviors, W as ORDER_GROUP_BASE, X as LocaleTables, Y as BASE_LOCALE, Z as Localization, _ as mergeStaticSignals, _t as SfxWave, a as clearBehaviors, at as Voice, b as Engine, bt as MusicBackend, c as registeredBehaviors, ct as ROLLOFF_MODELS, d as PropSchema, dt as Vec3, et as translationKey, f as clearRegistry, ft as spatialGain, g as getNodeType, gt as SfxParams, h as getNodeSignals, ht as SFX_PRESET_NAMES, i as behaviorSignals, it as isAudioContextAvailable, j as qualityEnvironment, jt as LogManager, k as Settings, kt as LogEntry, l as NodeCtor, lt as RolloffModel, m as getNodeSchema, mt as SFX_PRESETS, n as BehaviorCtor, nt as SfxEngine, o as getBehavior, ot as VoicePreset, p as createNode, pt as spatialPan, q as effectiveOrder, r as behaviorSchema, rt as SfxPlayOptions, s as registerBehavior, st as Listener, t as Behavior, tt as InputMap, u as PropDef, ut as SpatialParams, v as registerNode, vt as SynthOptions, w as GameStats, wt as AudioBuses, x as EngineOptions, xt as MusicManager, y as registeredTypes, yt as synthSfx, z as behaviorsWithoutSave } from "./behavior-62q0HWBO.js";
|
|
2
2
|
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-CFeioQRE.js";
|
|
3
|
-
import { n as loadScene, t as LoadSceneOptions } from "./loader-
|
|
3
|
+
import { n as loadScene, t as LoadSceneOptions } from "./loader-CeyU_bm1.js";
|
|
4
4
|
import { n as ParticleSimConfig, r as ParticleView, t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
5
|
-
import { a as AudioElementLike, i as gridFromRows, n as PathGrid, o as AudioPlayer, r as findPath, t as FindPathOptions } from "./pathfinding-
|
|
6
|
-
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-
|
|
5
|
+
import { a as AudioElementLike, i as gridFromRows, n as PathGrid, o as AudioPlayer, r as findPath, t as FindPathOptions } from "./pathfinding-C49JSNNq.js";
|
|
6
|
+
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-CAphXMyM.js";
|
|
7
7
|
|
|
8
8
|
//#region src/core/audio/crossfade.d.ts
|
|
9
9
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,177 +1,13 @@
|
|
|
1
1
|
import { C as getBehavior, E as Signal, S as clearBehaviors, T as registeredBehaviors, _ as InputMap, a as SCENE_FORMAT, b as behaviorSchema, c as SceneTree, d as resolveConstants, f as Node, g as resolveOrderGroups, h as effectiveOrder, i as serializeNode, l as CONST_REF_KEY, m as ORDER_GROUP_BASE, n as loadScene, o as computeViewport, p as parseNodePath, r as Scene, s as resolveViewport, u as isConstRef, w as registerBehavior, x as behaviorSignals, y as Behavior } from "./loader-r49nDwB4.js";
|
|
2
|
-
import { A as T_PREFIX, B as synthSfx, C as behaviorsWithoutSave, D as LogManager, E as createSaveStore, F as ROLLOFF_MODELS, G as AudioBuses, H as WebAudioMusicBackend, I as spatialGain, L as spatialPan, M as translationKey, N as SfxEngine, O as BASE_LOCALE, P as isAudioContextAvailable, R as SFX_PRESETS, S as SaveSlots, T as restoreBehaviors, U as crossfadeGains, V as MusicManager, W as fadeGain, a as UiSlider, b as readDeviceHints, c as UiButton, d as UiBanner, f as UiBar, g as Settings, h as Engine, i as UiSelect, j as suggestLocale, k as Localization, l as UiDialogue, m as AudioPlayer, n as UiImage, o as UiToggle, p as UiText, r as UiPanel, s as Timer, t as registerCoreNodes, u as HudLayer, v as qualityEnvironment, w as captureBehaviors, x as suggestQuality, z as SFX_PRESET_NAMES } from "./register-
|
|
2
|
+
import { A as T_PREFIX, B as synthSfx, C as behaviorsWithoutSave, D as LogManager, E as createSaveStore, F as ROLLOFF_MODELS, G as AudioBuses, H as WebAudioMusicBackend, I as spatialGain, L as spatialPan, M as translationKey, N as SfxEngine, O as BASE_LOCALE, P as isAudioContextAvailable, R as SFX_PRESETS, S as SaveSlots, T as restoreBehaviors, U as crossfadeGains, V as MusicManager, W as fadeGain, a as UiSlider, b as readDeviceHints, c as UiButton, d as UiBanner, f as UiBar, g as Settings, h as Engine, i as UiSelect, j as suggestLocale, k as Localization, l as UiDialogue, m as AudioPlayer, n as UiImage, o as UiToggle, p as UiText, r as UiPanel, s as Timer, t as registerCoreNodes, u as HudLayer, v as qualityEnvironment, w as captureBehaviors, x as suggestQuality, z as SFX_PRESET_NAMES } from "./register-BSXV8T9F.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
|
-
import { n as startRecording, r as auditScene, t as replay } from "./replay-
|
|
5
|
+
import { n as startRecording, r as auditScene, t as replay } from "./replay-DilbZgQI.js";
|
|
6
6
|
import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
7
7
|
import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-IyWCGe4q.js";
|
|
8
8
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
9
9
|
import { i as applyParticlePreset, n as PARTICLE_PRESETS, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-Bw7hB93B.js";
|
|
10
|
+
import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-CwYxzZKl.js";
|
|
10
11
|
import { i as resolveRendering, n as attachTouchControls, r as joystickVector, t as TouchControls } from "./touch-BoNg_MnF.js";
|
|
11
12
|
import { t as duplicateNode } from "./duplicate-CRtihGmC.js";
|
|
12
|
-
//#region src/core/pathfinding.ts
|
|
13
|
-
/**
|
|
14
|
-
* A* from `from` to `to` (inclusive cell coords). Returns the cell path
|
|
15
|
-
* INCLUDING both endpoints, or null when unreachable. Straight steps cost
|
|
16
|
-
* 1, diagonals √2; the heuristic is octile (admissible for both modes).
|
|
17
|
-
*/
|
|
18
|
-
function findPath(grid, from, to, opts) {
|
|
19
|
-
const [sx, sy] = from;
|
|
20
|
-
const [tx, ty] = to;
|
|
21
|
-
const { width, height } = grid;
|
|
22
|
-
const inBounds = (x, y) => x >= 0 && y >= 0 && x < width && y < height;
|
|
23
|
-
if (!inBounds(sx, sy) || !inBounds(tx, ty)) return null;
|
|
24
|
-
if (grid.solid(sx, sy) || grid.solid(tx, ty)) return null;
|
|
25
|
-
if (sx === tx && sy === ty) return [[sx, sy]];
|
|
26
|
-
const diagonal = opts?.diagonal ?? true;
|
|
27
|
-
const maxExpansions = opts?.maxExpansions ?? 2e4;
|
|
28
|
-
const idx = (x, y) => y * width + x;
|
|
29
|
-
const gScore = new Float64Array(width * height).fill(Number.POSITIVE_INFINITY);
|
|
30
|
-
const cameFrom = new Int32Array(width * height).fill(-1);
|
|
31
|
-
const closed = new Uint8Array(width * height);
|
|
32
|
-
const heap = [];
|
|
33
|
-
const fScore = new Float64Array(width * height).fill(Number.POSITIVE_INFINITY);
|
|
34
|
-
const push = (n) => {
|
|
35
|
-
heap.push(n);
|
|
36
|
-
let i = heap.length - 1;
|
|
37
|
-
while (i > 0) {
|
|
38
|
-
const p = i - 1 >> 1;
|
|
39
|
-
if (fScore[heap[p]] <= fScore[heap[i]]) break;
|
|
40
|
-
const t = heap[p];
|
|
41
|
-
heap[p] = heap[i];
|
|
42
|
-
heap[i] = t;
|
|
43
|
-
i = p;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const pop = () => {
|
|
47
|
-
const top = heap[0];
|
|
48
|
-
const last = heap.pop();
|
|
49
|
-
if (heap.length > 0) {
|
|
50
|
-
heap[0] = last;
|
|
51
|
-
let i = 0;
|
|
52
|
-
for (;;) {
|
|
53
|
-
const l = i * 2 + 1;
|
|
54
|
-
const r = l + 1;
|
|
55
|
-
let m = i;
|
|
56
|
-
if (l < heap.length && fScore[heap[l]] < fScore[heap[m]]) m = l;
|
|
57
|
-
if (r < heap.length && fScore[heap[r]] < fScore[heap[m]]) m = r;
|
|
58
|
-
if (m === i) break;
|
|
59
|
-
const t = heap[m];
|
|
60
|
-
heap[m] = heap[i];
|
|
61
|
-
heap[i] = t;
|
|
62
|
-
i = m;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return top;
|
|
66
|
-
};
|
|
67
|
-
const SQRT2 = Math.SQRT2;
|
|
68
|
-
const octile = (x, y) => {
|
|
69
|
-
const dx = Math.abs(x - tx);
|
|
70
|
-
const dy = Math.abs(y - ty);
|
|
71
|
-
return dx > dy ? dx - dy + SQRT2 * dy : dy - dx + SQRT2 * dx;
|
|
72
|
-
};
|
|
73
|
-
const start = idx(sx, sy);
|
|
74
|
-
gScore[start] = 0;
|
|
75
|
-
fScore[start] = octile(sx, sy);
|
|
76
|
-
push(start);
|
|
77
|
-
let expansions = 0;
|
|
78
|
-
while (heap.length > 0) {
|
|
79
|
-
if (++expansions > maxExpansions) return null;
|
|
80
|
-
const current = pop();
|
|
81
|
-
if (closed[current]) continue;
|
|
82
|
-
closed[current] = 1;
|
|
83
|
-
const cx = current % width;
|
|
84
|
-
const cy = current / width | 0;
|
|
85
|
-
if (cx === tx && cy === ty) {
|
|
86
|
-
const path = [];
|
|
87
|
-
let n = current;
|
|
88
|
-
while (n !== -1) {
|
|
89
|
-
path.push([n % width, n / width | 0]);
|
|
90
|
-
n = cameFrom[n];
|
|
91
|
-
}
|
|
92
|
-
path.reverse();
|
|
93
|
-
return path;
|
|
94
|
-
}
|
|
95
|
-
for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
|
|
96
|
-
if (dx === 0 && dy === 0) continue;
|
|
97
|
-
const isDiag = dx !== 0 && dy !== 0;
|
|
98
|
-
if (isDiag && !diagonal) continue;
|
|
99
|
-
const nx = cx + dx;
|
|
100
|
-
const ny = cy + dy;
|
|
101
|
-
if (!inBounds(nx, ny) || grid.solid(nx, ny)) continue;
|
|
102
|
-
if (isDiag && (grid.solid(cx + dx, cy) || grid.solid(cx, cy + dy))) continue;
|
|
103
|
-
const n = idx(nx, ny);
|
|
104
|
-
if (closed[n]) continue;
|
|
105
|
-
const tentative = gScore[current] + (isDiag ? SQRT2 : 1);
|
|
106
|
-
if (tentative < gScore[n]) {
|
|
107
|
-
gScore[n] = tentative;
|
|
108
|
-
fScore[n] = tentative + octile(nx, ny);
|
|
109
|
-
cameFrom[n] = current;
|
|
110
|
-
push(n);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
/** Build a PathGrid from row-strings ('#' = solid) — tests and tile games. */
|
|
117
|
-
function gridFromRows(rows) {
|
|
118
|
-
const height = rows.length;
|
|
119
|
-
return {
|
|
120
|
-
width: rows[0]?.length ?? 0,
|
|
121
|
-
height,
|
|
122
|
-
solid: (x, y) => (rows[y]?.[x] ?? "#") === "#"
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/core/preload.ts
|
|
127
|
-
/**
|
|
128
|
-
* Warm the HTTP cache for a list of asset urls with a progress callback —
|
|
129
|
-
* the loading-bar pattern every template ships. Failures only warn and still
|
|
130
|
-
* count toward progress (a broken url must not block the game), but they are
|
|
131
|
-
* reported in the result so callers can tell success from 100%-with-holes.
|
|
132
|
-
*/
|
|
133
|
-
async function preloadUrls(urls, onProgress) {
|
|
134
|
-
let loaded = 0;
|
|
135
|
-
const failed = [];
|
|
136
|
-
const total = urls.length;
|
|
137
|
-
if (total === 0) {
|
|
138
|
-
onProgress?.(0, 0);
|
|
139
|
-
return { failed };
|
|
140
|
-
}
|
|
141
|
-
await Promise.all(urls.map(async (url) => {
|
|
142
|
-
try {
|
|
143
|
-
await (await fetch(url)).arrayBuffer();
|
|
144
|
-
} catch (error) {
|
|
145
|
-
failed.push(url);
|
|
146
|
-
console.warn(`[incanto] preload failed for ${url}:`, error);
|
|
147
|
-
}
|
|
148
|
-
loaded += 1;
|
|
149
|
-
onProgress?.(loaded, total);
|
|
150
|
-
}));
|
|
151
|
-
return { failed };
|
|
152
|
-
}
|
|
153
|
-
/** Every url found in a scene's `assets` block (preload helper). */
|
|
154
|
-
function assetUrls(assets) {
|
|
155
|
-
return Object.values(assets ?? {}).map((a) => a.url).filter((u) => typeof u === "string" && !u.startsWith("data:"));
|
|
156
|
-
}
|
|
157
|
-
//#endregion
|
|
158
|
-
//#region src/core/uid-gen.ts
|
|
159
|
-
/**
|
|
160
|
-
* The ONE way to mint a node uid: crypto-strength, `n_` + 16 base36 chars
|
|
161
|
-
* (~82 bits). Hand-written uids are forbidden by convention — they break the
|
|
162
|
-
* collision-strength contract and read as fakes next to generated ones.
|
|
163
|
-
*/
|
|
164
|
-
function newUid() {
|
|
165
|
-
const bytes = new Uint8Array(16);
|
|
166
|
-
if (globalThis.crypto?.getRandomValues) globalThis.crypto.getRandomValues(bytes);
|
|
167
|
-
else for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
168
|
-
let id = "";
|
|
169
|
-
for (const b of bytes) id += (b % 36).toString(36);
|
|
170
|
-
return `n_${id.slice(0, 16)}`;
|
|
171
|
-
}
|
|
172
|
-
//#endregion
|
|
173
|
-
//#region src/index.ts
|
|
174
|
-
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
175
|
-
const VERSION = "0.41.0";
|
|
176
|
-
//#endregion
|
|
177
13
|
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiImage, UiPanel, UiSelect, UiSlider, UiText, UiToggle, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, 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, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveConstants, resolveOrderGroups, resolveRendering, resolveViewport, restoreBehaviors, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
package/dist/net.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Et as Node, Mt as Signal, b as Engine, d as PropSchema } from "./behavior-
|
|
1
|
+
import { Et as Node, Mt as Signal, b as Engine, d as PropSchema } from "./behavior-62q0HWBO.js";
|
|
2
2
|
import { c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/net/types.d.ts
|
package/dist/net.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as loadScene } from "./loader-r49nDwB4.js";
|
|
2
|
-
import { h as Engine } from "./register-
|
|
2
|
+
import { h as Engine } from "./register-BSXV8T9F.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
5
5
|
import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
|
|
6
|
-
import { i as applySyncPatch, n as NetworkSpawner, r as NetworkManager, t as registerNodesNet } from "./register-
|
|
6
|
+
import { i as applySyncPatch, n as NetworkSpawner, r as NetworkManager, t as registerNodesNet } from "./register-D651it1J.js";
|
|
7
7
|
//#region src/net/loopback.ts
|
|
8
8
|
/**
|
|
9
9
|
* In-memory multiplayer hub implementing the SAME kernel contract as
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { v as diagnose } from "./loader-r49nDwB4.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-R2JTnIMw.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
//#region src/2d/physics/physics-2d.ts
|
|
7
7
|
var physics_2d_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { v as diagnose } from "./loader-r49nDwB4.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { F as PhysicsBody3D, I as RigidBody3D, N as Area3D, P as CharacterBody3D, R as Node3D, z as validateCollider3D } from "./gameplay-
|
|
4
|
+
import { F as PhysicsBody3D, I as RigidBody3D, N as Area3D, P as CharacterBody3D, R as Node3D, z as validateCollider3D } from "./gameplay-BQOeAid6.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
|
-
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-
|
|
6
|
+
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-Ds5kXLoF.js";
|
|
7
7
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
8
8
|
//#region src/3d/physics/collider-lines.ts
|
|
9
9
|
/**
|
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-62q0HWBO.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-B3vBWgVD.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DFRbG0Bj.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -204,7 +204,9 @@ var WebAudioMusicBackend = class {
|
|
|
204
204
|
* frame to advance fades (the engine wires this to `updated`).
|
|
205
205
|
*
|
|
206
206
|
* ```ts
|
|
207
|
-
*
|
|
207
|
+
* // NOTE: the bundle ships SFX only — no music track. A background track is
|
|
208
|
+
* // your game's own file under public/, or a URL.
|
|
209
|
+
* engine.music.play('/audio/theme.mp3'); // loop, full
|
|
208
210
|
* engine.music.crossfadeTo('boss.mp3', 3); // 3s equal-power swap
|
|
209
211
|
* engine.music.stop(2); // fade out over 2s
|
|
210
212
|
* engine.music.setVolume(0.5); // per-manager volume
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { E as Signal, f as Node, t as buildNodeJson } from "./loader-r49nDwB4.js";
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
2
|
+
import { t as registerCoreNodes } from "./register-BSXV8T9F.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
5
5
|
import { l as registerNode } from "./registry-IyWCGe4q.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { f as Node, h as effectiveOrder } from "./loader-r49nDwB4.js";
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
2
|
+
import { t as registerCoreNodes } from "./register-BSXV8T9F.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { i as getNodeSchema, l as registerNode } from "./registry-IyWCGe4q.js";
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//#region src/core/pathfinding.ts
|
|
2
|
+
/**
|
|
3
|
+
* A* from `from` to `to` (inclusive cell coords). Returns the cell path
|
|
4
|
+
* INCLUDING both endpoints, or null when unreachable. Straight steps cost
|
|
5
|
+
* 1, diagonals √2; the heuristic is octile (admissible for both modes).
|
|
6
|
+
*/
|
|
7
|
+
function findPath(grid, from, to, opts) {
|
|
8
|
+
const [sx, sy] = from;
|
|
9
|
+
const [tx, ty] = to;
|
|
10
|
+
const { width, height } = grid;
|
|
11
|
+
const inBounds = (x, y) => x >= 0 && y >= 0 && x < width && y < height;
|
|
12
|
+
if (!inBounds(sx, sy) || !inBounds(tx, ty)) return null;
|
|
13
|
+
if (grid.solid(sx, sy) || grid.solid(tx, ty)) return null;
|
|
14
|
+
if (sx === tx && sy === ty) return [[sx, sy]];
|
|
15
|
+
const diagonal = opts?.diagonal ?? true;
|
|
16
|
+
const maxExpansions = opts?.maxExpansions ?? 2e4;
|
|
17
|
+
const idx = (x, y) => y * width + x;
|
|
18
|
+
const gScore = new Float64Array(width * height).fill(Number.POSITIVE_INFINITY);
|
|
19
|
+
const cameFrom = new Int32Array(width * height).fill(-1);
|
|
20
|
+
const closed = new Uint8Array(width * height);
|
|
21
|
+
const heap = [];
|
|
22
|
+
const fScore = new Float64Array(width * height).fill(Number.POSITIVE_INFINITY);
|
|
23
|
+
const push = (n) => {
|
|
24
|
+
heap.push(n);
|
|
25
|
+
let i = heap.length - 1;
|
|
26
|
+
while (i > 0) {
|
|
27
|
+
const p = i - 1 >> 1;
|
|
28
|
+
if (fScore[heap[p]] <= fScore[heap[i]]) break;
|
|
29
|
+
const t = heap[p];
|
|
30
|
+
heap[p] = heap[i];
|
|
31
|
+
heap[i] = t;
|
|
32
|
+
i = p;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const pop = () => {
|
|
36
|
+
const top = heap[0];
|
|
37
|
+
const last = heap.pop();
|
|
38
|
+
if (heap.length > 0) {
|
|
39
|
+
heap[0] = last;
|
|
40
|
+
let i = 0;
|
|
41
|
+
for (;;) {
|
|
42
|
+
const l = i * 2 + 1;
|
|
43
|
+
const r = l + 1;
|
|
44
|
+
let m = i;
|
|
45
|
+
if (l < heap.length && fScore[heap[l]] < fScore[heap[m]]) m = l;
|
|
46
|
+
if (r < heap.length && fScore[heap[r]] < fScore[heap[m]]) m = r;
|
|
47
|
+
if (m === i) break;
|
|
48
|
+
const t = heap[m];
|
|
49
|
+
heap[m] = heap[i];
|
|
50
|
+
heap[i] = t;
|
|
51
|
+
i = m;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return top;
|
|
55
|
+
};
|
|
56
|
+
const SQRT2 = Math.SQRT2;
|
|
57
|
+
const octile = (x, y) => {
|
|
58
|
+
const dx = Math.abs(x - tx);
|
|
59
|
+
const dy = Math.abs(y - ty);
|
|
60
|
+
return dx > dy ? dx - dy + SQRT2 * dy : dy - dx + SQRT2 * dx;
|
|
61
|
+
};
|
|
62
|
+
const start = idx(sx, sy);
|
|
63
|
+
gScore[start] = 0;
|
|
64
|
+
fScore[start] = octile(sx, sy);
|
|
65
|
+
push(start);
|
|
66
|
+
let expansions = 0;
|
|
67
|
+
while (heap.length > 0) {
|
|
68
|
+
if (++expansions > maxExpansions) return null;
|
|
69
|
+
const current = pop();
|
|
70
|
+
if (closed[current]) continue;
|
|
71
|
+
closed[current] = 1;
|
|
72
|
+
const cx = current % width;
|
|
73
|
+
const cy = current / width | 0;
|
|
74
|
+
if (cx === tx && cy === ty) {
|
|
75
|
+
const path = [];
|
|
76
|
+
let n = current;
|
|
77
|
+
while (n !== -1) {
|
|
78
|
+
path.push([n % width, n / width | 0]);
|
|
79
|
+
n = cameFrom[n];
|
|
80
|
+
}
|
|
81
|
+
path.reverse();
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
|
|
85
|
+
if (dx === 0 && dy === 0) continue;
|
|
86
|
+
const isDiag = dx !== 0 && dy !== 0;
|
|
87
|
+
if (isDiag && !diagonal) continue;
|
|
88
|
+
const nx = cx + dx;
|
|
89
|
+
const ny = cy + dy;
|
|
90
|
+
if (!inBounds(nx, ny) || grid.solid(nx, ny)) continue;
|
|
91
|
+
if (isDiag && (grid.solid(cx + dx, cy) || grid.solid(cx, cy + dy))) continue;
|
|
92
|
+
const n = idx(nx, ny);
|
|
93
|
+
if (closed[n]) continue;
|
|
94
|
+
const tentative = gScore[current] + (isDiag ? SQRT2 : 1);
|
|
95
|
+
if (tentative < gScore[n]) {
|
|
96
|
+
gScore[n] = tentative;
|
|
97
|
+
fScore[n] = tentative + octile(nx, ny);
|
|
98
|
+
cameFrom[n] = current;
|
|
99
|
+
push(n);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/** Build a PathGrid from row-strings ('#' = solid) — tests and tile games. */
|
|
106
|
+
function gridFromRows(rows) {
|
|
107
|
+
const height = rows.length;
|
|
108
|
+
return {
|
|
109
|
+
width: rows[0]?.length ?? 0,
|
|
110
|
+
height,
|
|
111
|
+
solid: (x, y) => (rows[y]?.[x] ?? "#") === "#"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/core/preload.ts
|
|
116
|
+
/**
|
|
117
|
+
* Warm the HTTP cache for a list of asset urls with a progress callback —
|
|
118
|
+
* the loading-bar pattern every template ships. Failures only warn and still
|
|
119
|
+
* count toward progress (a broken url must not block the game), but they are
|
|
120
|
+
* reported in the result so callers can tell success from 100%-with-holes.
|
|
121
|
+
*/
|
|
122
|
+
async function preloadUrls(urls, onProgress) {
|
|
123
|
+
let loaded = 0;
|
|
124
|
+
const failed = [];
|
|
125
|
+
const total = urls.length;
|
|
126
|
+
if (total === 0) {
|
|
127
|
+
onProgress?.(0, 0);
|
|
128
|
+
return { failed };
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(urls.map(async (url) => {
|
|
131
|
+
try {
|
|
132
|
+
await (await fetch(url)).arrayBuffer();
|
|
133
|
+
} catch (error) {
|
|
134
|
+
failed.push(url);
|
|
135
|
+
console.warn(`[incanto] preload failed for ${url}:`, error);
|
|
136
|
+
}
|
|
137
|
+
loaded += 1;
|
|
138
|
+
onProgress?.(loaded, total);
|
|
139
|
+
}));
|
|
140
|
+
return { failed };
|
|
141
|
+
}
|
|
142
|
+
/** Every url found in a scene's `assets` block (preload helper). */
|
|
143
|
+
function assetUrls(assets) {
|
|
144
|
+
return Object.values(assets ?? {}).map((a) => a.url).filter((u) => typeof u === "string" && !u.startsWith("data:"));
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/core/uid-gen.ts
|
|
148
|
+
/**
|
|
149
|
+
* The ONE way to mint a node uid: crypto-strength, `n_` + 16 base36 chars
|
|
150
|
+
* (~82 bits). Hand-written uids are forbidden by convention — they break the
|
|
151
|
+
* collision-strength contract and read as fakes next to generated ones.
|
|
152
|
+
*/
|
|
153
|
+
function newUid() {
|
|
154
|
+
const bytes = new Uint8Array(16);
|
|
155
|
+
if (globalThis.crypto?.getRandomValues) globalThis.crypto.getRandomValues(bytes);
|
|
156
|
+
else for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
157
|
+
let id = "";
|
|
158
|
+
for (const b of bytes) id += (b % 36).toString(36);
|
|
159
|
+
return `n_${id.slice(0, 16)}`;
|
|
160
|
+
}
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/index.ts
|
|
163
|
+
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
164
|
+
const VERSION = "0.43.0";
|
|
165
|
+
//#endregion
|
|
166
|
+
export { findPath as a, preloadUrls as i, newUid as n, gridFromRows as o, assetUrls as r, VERSION as t };
|