incanto 0.47.0 → 0.49.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-frame.mjs +58 -1
- package/bin/incanto-logs.mjs +127 -0
- package/bin/incanto-model.mjs +13 -1
- package/bin/incanto-playtest.mjs +7 -0
- package/bin/incanto-verify.mjs +41 -2
- package/dist/2d.d.ts +21 -12
- package/dist/2d.js +57 -3
- package/dist/3d.d.ts +38 -1
- package/dist/3d.js +114 -4
- package/dist/{create-game-CniOiWzN.js → create-game-BgV6UbVA.js} +5 -5
- package/dist/{create-game-D16MVIPO.js → create-game-DFBjMetZ.js} +83 -6
- package/dist/{duplicate-CRtihGmC.js → duplicate-CI9WF_bg.js} +1 -1
- package/dist/{environment-presets-D1b0ydTS.js → environment-presets-CZOH5TY5.js} +15 -20
- package/dist/{gameplay-BQOeAid6.js → gameplay-02Btmmjn.js} +80 -9
- package/dist/gameplay.d.ts +17 -0
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +139 -1
- package/dist/index.js +8 -7
- package/dist/{loader-r49nDwB4.js → loader-DwazzlQb.js} +36 -6
- package/dist/log-report-lxrQY9cH.js +0 -0
- package/dist/net.js +3 -3
- package/dist/{physics-2d-BmgXBNDB.js → physics-2d-vyCBfACH.js} +3 -3
- package/dist/{physics-3d-CSoGjM8P.js → physics-3d-DpRqw8Mz.js} +4 -4
- package/dist/react.js +1 -1
- package/dist/{register-R2JTnIMw.js → register-BNPZYJmd.js} +23 -22
- package/dist/{register-D651it1J.js → register-CB11yp21.js} +2 -2
- package/dist/{register-BSXV8T9F.js → register-uvaZj1KX.js} +62 -2
- package/dist/{replay-DilbZgQI.js → replay-C0XJIsO7.js} +1 -1
- package/dist/sprite-animation-CMr6f1K2.d.ts +44 -0
- package/dist/{particle-sim-Bw7hB93B.js → sprite-animation-D_p28jwU.js} +63 -1
- package/dist/{src-Ca3oV1fe.js → src-DF4gCsqO.js} +1 -1
- package/dist/{test-E4-otKqK.js → test-DRna_BQU.js} +210 -30
- package/dist/test.d.ts +38 -6
- package/dist/test.js +2 -2
- package/dist/vite.js +41 -4
- package/editor/assets/{agent8-_007gPF8.js → agent8-DCW4TgDt.js} +1 -1
- package/editor/assets/{debug-0DI_MJaq.js → debug-RC6qts6S.js} +1 -1
- package/editor/assets/{index-B-6eYZEi.js → index-5dEIhvsf.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +3 -2
- package/schemas/scene.schema.json +10 -3
- package/skills/incanto-3d-character.md +13 -2
- package/skills/incanto-3d-models.md +40 -0
- package/skills/incanto-assets.md +15 -0
- package/skills/incanto-building-2d-games.md +57 -5
- package/skills/incanto-building-3d-games.md +7 -0
- package/skills/incanto-gameplay-behaviors.md +18 -1
- package/skills/incanto-hud.md +39 -0
- package/skills/incanto-node-reference.md +5 -3
- package/skills/incanto-physics-and-input.md +1 -1
- package/skills/incanto-playtesting.md +9 -2
- package/skills/incanto-verifying-your-game.md +67 -0
- package/templates-app/beacon-isle-3d/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/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
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
3
|
import { n as loadScene, t as LoadSceneOptions } from "./loader-CeyU_bm1.js";
|
|
4
|
+
import { i as resolveFrames, n as AnimationEntry, r as resolveAnimation, t as AnimationDef } from "./sprite-animation-CMr6f1K2.js";
|
|
4
5
|
import { n as ParticleSimConfig, r as ParticleView, t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
5
6
|
import { a as AudioElementLike, i as gridFromRows, n as PathGrid, o as AudioPlayer, r as findPath, t as FindPathOptions } from "./pathfinding-C49JSNNq.js";
|
|
6
7
|
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";
|
|
@@ -69,6 +70,106 @@ interface DebugLineSource {
|
|
|
69
70
|
debugLines(): Float32Array | null;
|
|
70
71
|
}
|
|
71
72
|
//#endregion
|
|
73
|
+
//#region src/core/drive-script.d.ts
|
|
74
|
+
/**
|
|
75
|
+
* A little script for driving a game, in the words it already understands.
|
|
76
|
+
*
|
|
77
|
+
* `incanto-play` has driven scenes from bash for many releases — `press`,
|
|
78
|
+
* `vector`, `step` — and cannot show you the result, because headless has no
|
|
79
|
+
* pixels. `incanto-frame` has the pixels and cannot move. Between them an agent
|
|
80
|
+
* could only ever look at the boot screen, and every interesting state in a
|
|
81
|
+
* game is downstream of input: the boss room, the bridge, the moment after the
|
|
82
|
+
* jump.
|
|
83
|
+
*
|
|
84
|
+
* So the same vocabulary drives the RUNNING page, and the frame comes back
|
|
85
|
+
* after it. One language for both, or an agent has to learn two.
|
|
86
|
+
*
|
|
87
|
+
* Pure: parsing only. Who applies the steps is the page's business.
|
|
88
|
+
*/
|
|
89
|
+
type DriveStep = {
|
|
90
|
+
kind: "press";
|
|
91
|
+
action: string;
|
|
92
|
+
} | {
|
|
93
|
+
kind: "release";
|
|
94
|
+
action: string;
|
|
95
|
+
} | {
|
|
96
|
+
kind: "vector";
|
|
97
|
+
action: string;
|
|
98
|
+
x: number;
|
|
99
|
+
y: number;
|
|
100
|
+
} | {
|
|
101
|
+
kind: "key";
|
|
102
|
+
code: string;
|
|
103
|
+
down: boolean;
|
|
104
|
+
} | {
|
|
105
|
+
kind: "pointer";
|
|
106
|
+
dx: number;
|
|
107
|
+
dy: number;
|
|
108
|
+
} | {
|
|
109
|
+
kind: "step";
|
|
110
|
+
ms: number;
|
|
111
|
+
};
|
|
112
|
+
interface DriveScript {
|
|
113
|
+
steps: DriveStep[];
|
|
114
|
+
/** Why nothing will run, or null. A refused script runs NONE of its steps. */
|
|
115
|
+
error: string | null;
|
|
116
|
+
/** Total simulated time the script asks for, ms. */
|
|
117
|
+
totalMs: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* `vector move 0 1; step 2000` → steps, or an error naming the bad command.
|
|
121
|
+
*
|
|
122
|
+
* Semicolons and newlines both separate, so a whole plan fits in one shell
|
|
123
|
+
* argument and a longer one fits in a file. `#` starts a comment.
|
|
124
|
+
*
|
|
125
|
+
* A command it does not know REFUSES THE WHOLE SCRIPT. Skipping it would leave
|
|
126
|
+
* an agent looking at a frame that never moved, believing it had walked
|
|
127
|
+
* somewhere — the failure mode this exists to prevent.
|
|
128
|
+
*/
|
|
129
|
+
declare function parseDrive(text: string): DriveScript;
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/core/log-report.d.ts
|
|
132
|
+
interface AssetFailure {
|
|
133
|
+
ref: string;
|
|
134
|
+
url: string;
|
|
135
|
+
error: string;
|
|
136
|
+
}
|
|
137
|
+
interface LiveInput {
|
|
138
|
+
entries: readonly LogEntry[];
|
|
139
|
+
stats: EngineStats;
|
|
140
|
+
assetErrors: readonly AssetFailure[];
|
|
141
|
+
/**
|
|
142
|
+
* The page is one the browser has stopped drawing — hidden, or a window
|
|
143
|
+
* merely covered by another. It throttles such a tab to about a frame a
|
|
144
|
+
* second, and that number says nothing about the game.
|
|
145
|
+
*/
|
|
146
|
+
hidden?: boolean;
|
|
147
|
+
}
|
|
148
|
+
/** One message, however many times the game said it. */
|
|
149
|
+
interface GroupedLog {
|
|
150
|
+
level: LogLevel;
|
|
151
|
+
message: string;
|
|
152
|
+
count: number;
|
|
153
|
+
/** When it was last said, in the page's own clock. */
|
|
154
|
+
lastMs: number;
|
|
155
|
+
}
|
|
156
|
+
interface LiveReport {
|
|
157
|
+
ok: boolean;
|
|
158
|
+
/** Frame rate low enough to be felt (running, and not merely throttled). */
|
|
159
|
+
slow: boolean;
|
|
160
|
+
/** The browser is throttling this page — see {@link LiveInput.hidden}. */
|
|
161
|
+
hidden: boolean;
|
|
162
|
+
counts: Record<LogLevel, number>;
|
|
163
|
+
grouped: GroupedLog[];
|
|
164
|
+
/** The most severe thing said, or null when nothing was. */
|
|
165
|
+
worst: GroupedLog | null;
|
|
166
|
+
stats: EngineStats;
|
|
167
|
+
assetErrors: readonly AssetFailure[];
|
|
168
|
+
}
|
|
169
|
+
declare function logReport(input: LiveInput): LiveReport;
|
|
170
|
+
/** The report as a person or an agent reads it: what is wrong, then the numbers. */
|
|
171
|
+
declare function logText(r: LiveReport): string;
|
|
172
|
+
//#endregion
|
|
72
173
|
//#region src/core/node-path.d.ts
|
|
73
174
|
/**
|
|
74
175
|
* Godot-style NodePath grammar:
|
|
@@ -219,10 +320,37 @@ declare class UiText extends HudWidgetBase {
|
|
|
219
320
|
static override readonly typeName: string;
|
|
220
321
|
static override readonly props: PropSchema;
|
|
221
322
|
text: string;
|
|
323
|
+
/**
|
|
324
|
+
* A template with a `{}` slot that `setText` fills — `"Gems {} / 8"`.
|
|
325
|
+
*
|
|
326
|
+
* Empty (the default) means `setText` replaces the whole line. Resolved at
|
|
327
|
+
* PAINT like `text`, so `"@t:hud.gems"` works and changing locale re-reads
|
|
328
|
+
* it: the value lives here, the words live in the strings table.
|
|
329
|
+
*/
|
|
330
|
+
format: string;
|
|
222
331
|
size: number;
|
|
223
332
|
color: string;
|
|
224
333
|
shadow: boolean;
|
|
225
334
|
private last;
|
|
335
|
+
/** null until something has actually set a value — see `shown`. */
|
|
336
|
+
private slot;
|
|
337
|
+
/**
|
|
338
|
+
* Put a signal's value on screen — `scoreChanged → setText`.
|
|
339
|
+
*
|
|
340
|
+
* A `connections[]` handler must be a METHOD and `text` is a property, so the
|
|
341
|
+
* one wire every game needs (score to screen) could not be declared: every
|
|
342
|
+
* HUD began with a behavior whose whole job was one assignment.
|
|
343
|
+
*/
|
|
344
|
+
setText(value: unknown): void;
|
|
345
|
+
/**
|
|
346
|
+
* What it actually paints, after the template and the locale.
|
|
347
|
+
*
|
|
348
|
+
* Before the first value arrives, a formatted widget shows `text` — its
|
|
349
|
+
* authored opening line. Filling the slot with nothing instead would put
|
|
350
|
+
* `"Gems / 8"` on screen for every game's first frame, and a score line
|
|
351
|
+
* that starts blank looks broken rather than empty.
|
|
352
|
+
*/
|
|
353
|
+
get shown(): string;
|
|
226
354
|
protected _build(): HTMLElement;
|
|
227
355
|
protected override _sync(): void;
|
|
228
356
|
}
|
|
@@ -245,6 +373,16 @@ declare class UiBar extends HudWidgetBase {
|
|
|
245
373
|
private lastRatio;
|
|
246
374
|
/** Current fill ratio 0..1 (what the bar shows). */
|
|
247
375
|
get ratio(): number;
|
|
376
|
+
/**
|
|
377
|
+
* Drive the bar from a signal — `healthChanged → setValue`.
|
|
378
|
+
*
|
|
379
|
+
* Takes the max as a second argument because that is the shape the signal
|
|
380
|
+
* already has, so a bar whose ceiling moves (a max-HP upgrade) needs no
|
|
381
|
+
* second wire.
|
|
382
|
+
*/
|
|
383
|
+
setValue(value: number, max?: number): void;
|
|
384
|
+
/** Move the ceiling on its own, leaving the fill where it is. */
|
|
385
|
+
setMax(max: number): void;
|
|
248
386
|
protected _build(): HTMLElement;
|
|
249
387
|
protected override _sync(): void;
|
|
250
388
|
}
|
|
@@ -710,4 +848,4 @@ declare function computeViewport(canvasW: number, canvasH: number, viewport: {
|
|
|
710
848
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
711
849
|
declare const VERSION: string;
|
|
712
850
|
//#endregion
|
|
713
|
-
export { AudioBuses, type AudioElementLike, AudioPlayer, BASE_LOCALE, Behavior, type BehaviorCtor, type BehaviorState, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, type DeviceHints, 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 LocaleTables, Localization, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, type OrderGroupTable, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PathGrid, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, type QualityTier, ROLLOFF_MODELS, type Recorder, type RendererStats, type ReplayEvent, type ReplayJson, type ResolvedRendering, type ResolvedViewport, type RestoreReport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveSlot, SaveSlots, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, Settings, type SettingsValues, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, T_PREFIX, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiButton, UiDialogue, UiImage, UiPanel, UiSelect, UiSlider, UiText, UiToggle, VERSION, type Vec3, type ViewportFit, type Voice, type VoicePreset, 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 };
|
|
851
|
+
export { type AnimationDef, type AnimationEntry, type AssetFailure, AudioBuses, type AudioElementLike, AudioPlayer, BASE_LOCALE, Behavior, type BehaviorCtor, type BehaviorState, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, type DeviceHints, type DriveScript, type DriveStep, Engine, type EngineOptions, type EngineStats, type FindPathOptions, type GameStats, type GroupedLog, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LiveInput, type LiveReport, type LoadSceneOptions, type LocaleTables, Localization, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, type OrderGroupTable, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PathGrid, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, type QualityTier, ROLLOFF_MODELS, type Recorder, type RendererStats, type ReplayEvent, type ReplayJson, type ResolvedRendering, type ResolvedViewport, type RestoreReport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveSlot, SaveSlots, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, Settings, type SettingsValues, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, T_PREFIX, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiButton, UiDialogue, UiImage, UiPanel, UiSelect, UiSlider, UiText, UiToggle, VERSION, type Vec3, type ViewportFit, type Voice, type VoicePreset, 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, logReport, logText, mergeStaticSignals, newUid, parseDrive, parseNodePath, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRendering, resolveViewport, restoreBehaviors, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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-
|
|
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-
|
|
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-DwazzlQb.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-uvaZj1KX.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-C0XJIsO7.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
|
+
import { n as logText, r as parseDrive, t as logReport } from "./log-report-lxrQY9cH.js";
|
|
8
9
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
9
|
-
import { i as
|
|
10
|
-
import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-
|
|
10
|
+
import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-D_p28jwU.js";
|
|
11
|
+
import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-DF4gCsqO.js";
|
|
11
12
|
import { i as resolveRendering, n as attachTouchControls, r as joystickVector, t as TouchControls } from "./touch-BoNg_MnF.js";
|
|
12
|
-
import { t as duplicateNode } from "./duplicate-
|
|
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 };
|
|
13
|
+
import { t as duplicateNode } from "./duplicate-CI9WF_bg.js";
|
|
14
|
+
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, logReport, logText, mergeStaticSignals, newUid, parseDrive, parseNodePath, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRendering, resolveViewport, restoreBehaviors, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -1606,13 +1606,17 @@ function wireConnections(root, connections, declareSignals = false) {
|
|
|
1606
1606
|
const listener = (...args) => {
|
|
1607
1607
|
if (conn.filter && !matchesFilter(args[0], conn.filter)) return;
|
|
1608
1608
|
if (conn.once) fromNode.off(conn.signal, listener);
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1609
|
+
try {
|
|
1610
|
+
const fn = toNode[conn.handler];
|
|
1611
|
+
if (typeof fn === "function") {
|
|
1612
|
+
fn.apply(toNode, args);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
const bfn = toNode.behavior ? toNode.behavior[conn.handler] : void 0;
|
|
1616
|
+
if (typeof bfn === "function") bfn.apply(toNode.behavior, args);
|
|
1617
|
+
} catch (error) {
|
|
1618
|
+
quarantineWire(fromNode, toNode, conn, listener, error);
|
|
1613
1619
|
}
|
|
1614
|
-
const bfn = toNode.behavior ? toNode.behavior[conn.handler] : void 0;
|
|
1615
|
-
if (typeof bfn === "function") bfn.apply(toNode.behavior, args);
|
|
1616
1620
|
};
|
|
1617
1621
|
try {
|
|
1618
1622
|
fromNode.on(conn.signal, listener);
|
|
@@ -1622,6 +1626,32 @@ function wireConnections(root, connections, declareSignals = false) {
|
|
|
1622
1626
|
}
|
|
1623
1627
|
}
|
|
1624
1628
|
}
|
|
1629
|
+
/**
|
|
1630
|
+
* A handler threw. Turn THAT WIRE off, and leave the game running.
|
|
1631
|
+
*
|
|
1632
|
+
* The engine already draws this line for scripts: "a behavior is your code; the
|
|
1633
|
+
* node is the engine's. A typo in the first must not switch off the second, or
|
|
1634
|
+
* breaking a sword script stops the character from walking." A connection is
|
|
1635
|
+
* the same category — authored wiring, not the emitting node's own logic — and
|
|
1636
|
+
* it behaved the opposite way, because the handler runs inside `Signal.emit`
|
|
1637
|
+
* and its exception surfaces in whoever EMITTED. The node quarantine then blames
|
|
1638
|
+
* and skips that node, so a `movementStateChanged → play` wire naming a clip the
|
|
1639
|
+
* sheet does not have switched off the character controller: no animation, and
|
|
1640
|
+
* no movement either.
|
|
1641
|
+
*
|
|
1642
|
+
* Reported ONCE and disconnected, on the same reasoning as the node quarantine:
|
|
1643
|
+
* a handler that throws throws every frame, and sixty identical traces a second
|
|
1644
|
+
* bury the one line that matters.
|
|
1645
|
+
*/
|
|
1646
|
+
function quarantineWire(fromNode, toNode, conn, listener, error) {
|
|
1647
|
+
fromNode.off(conn.signal, listener);
|
|
1648
|
+
const target = toNode.behavior ? `'${conn.handler}' on behavior '${toNode.script?.name}' (${toNode.getPath()})` : `'${conn.handler}' on ${toNode.getPath()}`;
|
|
1649
|
+
const message = `[incanto] connection '${conn.signal}' from ${fromNode.getPath()} → handler ${target} threw — THIS WIRE is now off; the node that emitted the signal, and the rest of the scene, keep running.`;
|
|
1650
|
+
const engine = toNode.tree?.engine ?? fromNode.tree?.engine;
|
|
1651
|
+
engine?.log.error(message, error);
|
|
1652
|
+
engine?._nodeErrored(toNode);
|
|
1653
|
+
console.error(message, error);
|
|
1654
|
+
}
|
|
1625
1655
|
function resolveEndpoint(root, path, conn, side) {
|
|
1626
1656
|
try {
|
|
1627
1657
|
return root.getNode(path);
|
|
Binary file
|
package/dist/net.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as loadScene } from "./loader-
|
|
2
|
-
import { h as Engine } from "./register-
|
|
1
|
+
import { n as loadScene } from "./loader-DwazzlQb.js";
|
|
2
|
+
import { h as Engine } from "./register-uvaZj1KX.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-CB11yp21.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
|
-
import { v as diagnose } from "./loader-
|
|
2
|
+
import { v as diagnose } from "./loader-DwazzlQb.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-BNPZYJmd.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({
|
|
@@ -122,7 +122,7 @@ var Physics2D = class {
|
|
|
122
122
|
moveAndSlide(node) {
|
|
123
123
|
const e = this.ensureEntry(node);
|
|
124
124
|
const vy = node.velocity[1] ?? 0;
|
|
125
|
-
if (node.
|
|
125
|
+
if (node.stickToGround && vy >= 0) this.kcc.enableSnapToGround(.05);
|
|
126
126
|
else this.kcc.disableSnapToGround();
|
|
127
127
|
this.kcc.setMaxSlopeClimbAngle(node.slopeLimitDeg * DEG);
|
|
128
128
|
let carryX = 0;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { v as diagnose } from "./loader-
|
|
2
|
+
import { v as diagnose } from "./loader-DwazzlQb.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-02Btmmjn.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-CZOH5TY5.js";
|
|
7
7
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
8
8
|
//#region src/3d/physics/collider-lines.ts
|
|
9
9
|
/**
|
|
@@ -373,7 +373,7 @@ var Physics3D = class {
|
|
|
373
373
|
const e = this.ensureEntry(node);
|
|
374
374
|
if (!e) return;
|
|
375
375
|
const vy = node.velocity[1] ?? 0;
|
|
376
|
-
if (node.
|
|
376
|
+
if (node.stickToGround && vy <= 0) this.kcc.enableSnapToGround(.1);
|
|
377
377
|
else this.kcc.disableSnapToGround();
|
|
378
378
|
this.kcc.setMaxSlopeClimbAngle(node.slopeLimitDeg * DEG);
|
|
379
379
|
let carryX = 0;
|
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-DFBjMetZ.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-BgV6UbVA.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { f as Node, h as effectiveOrder } from "./loader-
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
1
|
+
import { f as Node, h as effectiveOrder } from "./loader-DwazzlQb.js";
|
|
2
|
+
import { t as registerCoreNodes } from "./register-uvaZj1KX.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";
|
|
6
|
-
import { i as
|
|
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-D_p28jwU.js";
|
|
7
7
|
import { AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture, Color, DynamicDrawUsage, Group, InstancedMesh, MathUtils, Matrix4, Mesh, MeshBasicMaterial, NearestFilter, NormalBlending, Object3D, PlaneGeometry } from "three";
|
|
8
8
|
//#region src/2d/physics/collider-validate.ts
|
|
9
9
|
/**
|
|
@@ -198,13 +198,19 @@ var CharacterBody2D = class extends PhysicsBody2D {
|
|
|
198
198
|
static typeName = "CharacterBody2D";
|
|
199
199
|
static props = {
|
|
200
200
|
velocity: { default: [0, 0] },
|
|
201
|
-
|
|
201
|
+
stickToGround: { default: true },
|
|
202
202
|
slopeLimitDeg: { default: 45 }
|
|
203
203
|
};
|
|
204
|
+
/**
|
|
205
|
+
* Renamed to match the 3D body, where `snapToGround` had to give the name
|
|
206
|
+
* back to `Node3D`'s PLACEMENT prop. 2D has no placement prop, so nothing is
|
|
207
|
+
* ambiguous here and old scenes keep loading unchanged.
|
|
208
|
+
*/
|
|
209
|
+
static propAliases = { snapToGround: "stickToGround" };
|
|
204
210
|
/** px/s, y-down (up = -y). */
|
|
205
211
|
velocity = [0, 0];
|
|
206
212
|
/** Keep contact on slopes/steps while not moving upward. */
|
|
207
|
-
|
|
213
|
+
stickToGround = true;
|
|
208
214
|
/** Max climbable slope angle. */
|
|
209
215
|
slopeLimitDeg = 45;
|
|
210
216
|
/** @internal Updated by Physics2D.moveAndSlide. */
|
|
@@ -402,13 +408,19 @@ var AnimatedSprite2D = class extends Sprite2D {
|
|
|
402
408
|
frameList = [];
|
|
403
409
|
frameIndex = 0;
|
|
404
410
|
frameTime = 0;
|
|
411
|
+
currentDef = null;
|
|
405
412
|
ownTexture = null;
|
|
406
413
|
loadedSheetRef = "";
|
|
414
|
+
/**
|
|
415
|
+
* `currentAnimation` reports the clip that is RUNNING, not the name asked
|
|
416
|
+
* for: an alias is a rename, and a state machine that reads back `fall` while
|
|
417
|
+
* the idle frames play is describing something that is not happening.
|
|
418
|
+
*/
|
|
407
419
|
play(name) {
|
|
408
|
-
const def = this.animations
|
|
409
|
-
|
|
410
|
-
this.
|
|
411
|
-
this.frameList = resolveFrames(def.frames,
|
|
420
|
+
const { name: resolved, def } = resolveAnimation(this.animations, name, this.name);
|
|
421
|
+
this.currentAnimation = resolved;
|
|
422
|
+
this.currentDef = def;
|
|
423
|
+
this.frameList = resolveFrames(def.frames, resolved);
|
|
412
424
|
this.frameIndex = 0;
|
|
413
425
|
this.currentFrame = this.frameList[0] ?? 0;
|
|
414
426
|
this.frameTime = 0;
|
|
@@ -418,11 +430,12 @@ var AnimatedSprite2D = class extends Sprite2D {
|
|
|
418
430
|
this.playing = false;
|
|
419
431
|
}
|
|
420
432
|
onReady() {
|
|
433
|
+
validateAnimationAliases(this.animations, this.name);
|
|
421
434
|
if (this.autoplay) this.play(this.autoplay);
|
|
422
435
|
}
|
|
423
436
|
update(dt) {
|
|
424
437
|
if (!this.playing || this.currentAnimation === "") return;
|
|
425
|
-
const def = this.
|
|
438
|
+
const def = this.currentDef;
|
|
426
439
|
if (!def || !Number.isFinite(def.fps) || def.fps <= 0) return;
|
|
427
440
|
const perFrame = 1 / def.fps;
|
|
428
441
|
this.frameTime += dt;
|
|
@@ -462,18 +475,6 @@ var AnimatedSprite2D = class extends Sprite2D {
|
|
|
462
475
|
};
|
|
463
476
|
}
|
|
464
477
|
};
|
|
465
|
-
function resolveFrames(frames, name) {
|
|
466
|
-
if (!Array.isArray(frames) || frames.length === 0) throw new IncantoError("BAD_FORMAT", `Animation '${name}': "frames" must be a non-empty array.`);
|
|
467
|
-
if (frames.length === 2) {
|
|
468
|
-
const [start, end] = frames;
|
|
469
|
-
if (end >= start) {
|
|
470
|
-
const out = [];
|
|
471
|
-
for (let f = start; f <= end; f++) out.push(f);
|
|
472
|
-
return out;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
return [...frames];
|
|
476
|
-
}
|
|
477
478
|
//#endregion
|
|
478
479
|
//#region src/2d/nodes/camera-2d.ts
|
|
479
480
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as Signal, f as Node, t as buildNodeJson } from "./loader-
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
1
|
+
import { E as Signal, f as Node, t as buildNodeJson } from "./loader-DwazzlQb.js";
|
|
2
|
+
import { t as registerCoreNodes } from "./register-uvaZj1KX.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,4 +1,4 @@
|
|
|
1
|
-
import { E as Signal, _ as InputMap, b as behaviorSchema, f as Node, g as resolveOrderGroups, m as ORDER_GROUP_BASE, v as diagnose } from "./loader-
|
|
1
|
+
import { E as Signal, _ as InputMap, b as behaviorSchema, f as Node, g as resolveOrderGroups, m as ORDER_GROUP_BASE, v as diagnose } from "./loader-DwazzlQb.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
4
|
import { l as registerNode } from "./registry-IyWCGe4q.js";
|
|
@@ -2558,28 +2558,73 @@ var UiText = class extends HudWidgetBase {
|
|
|
2558
2558
|
static props = {
|
|
2559
2559
|
...HudWidgetBase.props,
|
|
2560
2560
|
text: { default: "" },
|
|
2561
|
+
format: { default: "" },
|
|
2561
2562
|
size: { default: 16 },
|
|
2562
2563
|
color: { default: "#ffffff" },
|
|
2563
2564
|
shadow: { default: true }
|
|
2564
2565
|
};
|
|
2565
2566
|
text = "";
|
|
2567
|
+
/**
|
|
2568
|
+
* A template with a `{}` slot that `setText` fills — `"Gems {} / 8"`.
|
|
2569
|
+
*
|
|
2570
|
+
* Empty (the default) means `setText` replaces the whole line. Resolved at
|
|
2571
|
+
* PAINT like `text`, so `"@t:hud.gems"` works and changing locale re-reads
|
|
2572
|
+
* it: the value lives here, the words live in the strings table.
|
|
2573
|
+
*/
|
|
2574
|
+
format = "";
|
|
2566
2575
|
size = 16;
|
|
2567
2576
|
color = "#ffffff";
|
|
2568
2577
|
shadow = true;
|
|
2569
2578
|
last = "\0";
|
|
2579
|
+
/** null until something has actually set a value — see `shown`. */
|
|
2580
|
+
slot = null;
|
|
2581
|
+
/**
|
|
2582
|
+
* Put a signal's value on screen — `scoreChanged → setText`.
|
|
2583
|
+
*
|
|
2584
|
+
* A `connections[]` handler must be a METHOD and `text` is a property, so the
|
|
2585
|
+
* one wire every game needs (score to screen) could not be declared: every
|
|
2586
|
+
* HUD began with a behavior whose whole job was one assignment.
|
|
2587
|
+
*/
|
|
2588
|
+
setText(value) {
|
|
2589
|
+
this.slot = String(value ?? "");
|
|
2590
|
+
if (!this.format) this.text = this.slot;
|
|
2591
|
+
}
|
|
2592
|
+
/**
|
|
2593
|
+
* What it actually paints, after the template and the locale.
|
|
2594
|
+
*
|
|
2595
|
+
* Before the first value arrives, a formatted widget shows `text` — its
|
|
2596
|
+
* authored opening line. Filling the slot with nothing instead would put
|
|
2597
|
+
* `"Gems / 8"` on screen for every game's first frame, and a score line
|
|
2598
|
+
* that starts blank looks broken rather than empty.
|
|
2599
|
+
*/
|
|
2600
|
+
get shown() {
|
|
2601
|
+
if (this.format && this.slot !== null) return this._t(this.format).replace("{}", this.slot);
|
|
2602
|
+
return this._t(this.text);
|
|
2603
|
+
}
|
|
2570
2604
|
_build() {
|
|
2571
2605
|
const el = document.createElement("div");
|
|
2572
2606
|
el.style.cssText = `font-size:${this.size}px;color:${this.color};${this.shadow ? "text-shadow:0 1px 3px rgba(0,0,0,.7);" : ""}white-space:pre;`;
|
|
2573
2607
|
return el;
|
|
2574
2608
|
}
|
|
2575
2609
|
_sync() {
|
|
2576
|
-
const shown = this.
|
|
2610
|
+
const shown = this.shown;
|
|
2577
2611
|
if (shown !== this.last && this._element) {
|
|
2578
2612
|
this.last = shown;
|
|
2579
2613
|
this._element.textContent = shown;
|
|
2580
2614
|
}
|
|
2581
2615
|
}
|
|
2582
2616
|
};
|
|
2617
|
+
/**
|
|
2618
|
+
* A bar fed the wrong argument shows a plausible wrong number forever.
|
|
2619
|
+
*
|
|
2620
|
+
* The trap is one signal away: `Health.damaged` is `(amount, current)`, so
|
|
2621
|
+
* wiring it to `setValue` paints the DAMAGE as the health and looks like a
|
|
2622
|
+
* working health bar. Say which signal has the shape a bar wants.
|
|
2623
|
+
*/
|
|
2624
|
+
function requireNumber(value, node, method) {
|
|
2625
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2626
|
+
throw new IncantoError("PROP_TYPE_MISMATCH", `UiBar '${node.getPath()}'.${method} needs a number, got ${JSON.stringify(value)}. Check what the wired signal passes FIRST — 'damaged' is (amount, current), 'healthChanged' is (current, max), which is the shape a bar wants.`);
|
|
2627
|
+
}
|
|
2583
2628
|
/** A labeled progress bar (health, stamina, reload, boss HP). */
|
|
2584
2629
|
var UiBar = class extends HudWidgetBase {
|
|
2585
2630
|
static typeName = "UiBar";
|
|
@@ -2612,6 +2657,21 @@ var UiBar = class extends HudWidgetBase {
|
|
|
2612
2657
|
get ratio() {
|
|
2613
2658
|
return this.max > 0 ? Math.min(1, Math.max(0, this.value / this.max)) : 0;
|
|
2614
2659
|
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Drive the bar from a signal — `healthChanged → setValue`.
|
|
2662
|
+
*
|
|
2663
|
+
* Takes the max as a second argument because that is the shape the signal
|
|
2664
|
+
* already has, so a bar whose ceiling moves (a max-HP upgrade) needs no
|
|
2665
|
+
* second wire.
|
|
2666
|
+
*/
|
|
2667
|
+
setValue(value, max) {
|
|
2668
|
+
this.value = requireNumber(value, this, "setValue");
|
|
2669
|
+
if (max !== void 0) this.max = requireNumber(max, this, "setValue");
|
|
2670
|
+
}
|
|
2671
|
+
/** Move the ceiling on its own, leaving the fill where it is. */
|
|
2672
|
+
setMax(max) {
|
|
2673
|
+
this.max = requireNumber(max, this, "setMax");
|
|
2674
|
+
}
|
|
2615
2675
|
_build() {
|
|
2616
2676
|
const wrap = document.createElement("div");
|
|
2617
2677
|
wrap.style.cssText = "display:flex;align-items:center;gap:6px;";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/core/sprite-animation.d.ts
|
|
2
|
+
interface AnimationDef {
|
|
3
|
+
/**
|
|
4
|
+
* Two numbers = inclusive [start, end] frame RANGE.
|
|
5
|
+
* Any other length = explicit frame list.
|
|
6
|
+
*/
|
|
7
|
+
frames: number[];
|
|
8
|
+
fps: number;
|
|
9
|
+
loop?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A clip, or the NAME of another clip in the same map.
|
|
13
|
+
*
|
|
14
|
+
* The alias exists because the character a game is built from and the character
|
|
15
|
+
* a controller describes are not the same vocabulary.
|
|
16
|
+
* `CharacterController2D`/`3D` emit `idle`/`run`/`jump`/`fall`/`wallSlide`/
|
|
17
|
+
* `dash`; the sheets in the engine's own catalog carry `idle`/`move`/`attack`,
|
|
18
|
+
* and no sheet anywhere ships a `fall`. So the documented one-line wiring —
|
|
19
|
+
* `movementStateChanged → play` — asked for clips that do not exist, and the
|
|
20
|
+
* hard error was correct and useless: there is nothing to rename it TO.
|
|
21
|
+
*
|
|
22
|
+
* An alias is the missing half. `"fall": "idle"` says what to show while
|
|
23
|
+
* falling, in the scene, next to everything else about that character.
|
|
24
|
+
*/
|
|
25
|
+
type AnimationEntry = AnimationDef | string;
|
|
26
|
+
/**
|
|
27
|
+
* Follow aliases to the clip that actually plays.
|
|
28
|
+
*
|
|
29
|
+
* Chains are allowed (`fall → jump → idle`) because they are how a fallback
|
|
30
|
+
* ladder reads, and a cycle is a hard error rather than a hang.
|
|
31
|
+
*/
|
|
32
|
+
declare function resolveAnimation(animations: Record<string, AnimationEntry>, name: string, owner: string): {
|
|
33
|
+
name: string;
|
|
34
|
+
def: AnimationDef;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* `[start, end]` is a RANGE; anything else is an explicit list.
|
|
38
|
+
*
|
|
39
|
+
* Two ascending numbers are overwhelmingly a range in every sheet format, and
|
|
40
|
+
* a two-frame flip-book is spelled `[3, 3, 4, 4]` or a descending pair.
|
|
41
|
+
*/
|
|
42
|
+
declare function resolveFrames(frames: number[], name: string): number[];
|
|
43
|
+
//#endregion
|
|
44
|
+
export { resolveFrames as i, AnimationEntry as n, resolveAnimation as r, AnimationDef as t };
|