incanto 0.1.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.
Files changed (138) hide show
  1. package/LICENSE +30 -0
  2. package/README.md +36 -0
  3. package/THIRD-PARTY-NOTICES.md +88 -0
  4. package/assets/audio/attacked.mp3 +0 -0
  5. package/assets/audio/explosion.mp3 +0 -0
  6. package/assets/audio/gold_loot.mp3 +0 -0
  7. package/assets/audio/heal.mp3 +0 -0
  8. package/assets/audio/hit_metal_bang.mp3 +0 -0
  9. package/assets/audio/ice_spear.mp3 +0 -0
  10. package/assets/audio/monster_died.mp3 +0 -0
  11. package/assets/audio/slash.mp3 +0 -0
  12. package/assets/audio/smite.mp3 +0 -0
  13. package/assets/audio/spells_cast.mp3 +0 -0
  14. package/assets/audio/ui_click.wav +0 -0
  15. package/assets/audio/walk.mp3 +0 -0
  16. package/assets/catalog.json +390 -0
  17. package/assets/characters/2dbasic.json +41 -0
  18. package/assets/characters/2dbasic.png +0 -0
  19. package/assets/characters/ghost.json +46 -0
  20. package/assets/characters/ghost.png +0 -0
  21. package/assets/characters/goblin.json +40 -0
  22. package/assets/characters/goblin.png +0 -0
  23. package/assets/characters/medieval-knight.json +41 -0
  24. package/assets/characters/medieval-knight.png +0 -0
  25. package/assets/effects/swoosh.png +0 -0
  26. package/assets/items/box.png +0 -0
  27. package/assets/items/buff_potion.png +0 -0
  28. package/assets/items/coin.png +0 -0
  29. package/assets/items/gem.png +0 -0
  30. package/assets/items/gold.png +0 -0
  31. package/assets/items/hp_potion.png +0 -0
  32. package/assets/items/locked_item_box.png +0 -0
  33. package/assets/items/map.png +0 -0
  34. package/assets/items/resurrection_potion.png +0 -0
  35. package/assets/items/super_box.png +0 -0
  36. package/assets/items/trap.png +0 -0
  37. package/assets/tiles/floor00.jpg +0 -0
  38. package/assets/tiles/minecraft-tiles.png +0 -0
  39. package/assets/tiles/wall00.jpg +0 -0
  40. package/assets/vegetation/ash_color.png +0 -0
  41. package/assets/vegetation/aspen_color.png +0 -0
  42. package/assets/vegetation/bark/birch_color_1k.jpg +0 -0
  43. package/assets/vegetation/bark/birch_normal_1k.jpg +0 -0
  44. package/assets/vegetation/bark/birch_roughness_1k.jpg +0 -0
  45. package/assets/vegetation/bark/oak_color_1k.jpg +0 -0
  46. package/assets/vegetation/bark/oak_normal_1k.jpg +0 -0
  47. package/assets/vegetation/bark/oak_roughness_1k.jpg +0 -0
  48. package/assets/vegetation/bark/pine_color_1k.jpg +0 -0
  49. package/assets/vegetation/bark/pine_normal_1k.jpg +0 -0
  50. package/assets/vegetation/bark/pine_roughness_1k.jpg +0 -0
  51. package/assets/vegetation/ground/dirt_color.jpg +0 -0
  52. package/assets/vegetation/ground/dirt_normal.jpg +0 -0
  53. package/assets/vegetation/ground/grass.jpg +0 -0
  54. package/assets/vegetation/oak_color.png +0 -0
  55. package/assets/vegetation/pine_color.png +0 -0
  56. package/bin/incanto-assets.mjs +107 -0
  57. package/bin/incanto-check.mjs +107 -0
  58. package/bin/incanto-editor.mjs +343 -0
  59. package/bin/incanto-env.mjs +144 -0
  60. package/bin/incanto-model.mjs +296 -0
  61. package/bin/incanto-play.mjs +219 -0
  62. package/bin/incanto-skills.mjs +71 -0
  63. package/dist/2d.d.ts +642 -0
  64. package/dist/2d.js +44 -0
  65. package/dist/3d.d.ts +1860 -0
  66. package/dist/3d.js +5 -0
  67. package/dist/agent8-DzU2fFyH.js +129 -0
  68. package/dist/audio-player-DqUR3XFs.d.ts +110 -0
  69. package/dist/behavior-BAQq7HGM.d.ts +851 -0
  70. package/dist/create-game-BdjpTHrW.js +1725 -0
  71. package/dist/create-game-CZHROKcT.js +527 -0
  72. package/dist/debug-draw-CZmOYjL2.js +13 -0
  73. package/dist/debug.d.ts +66 -0
  74. package/dist/debug.js +658 -0
  75. package/dist/duplicate-DP2WPYom.js +22 -0
  76. package/dist/env.d.ts +430 -0
  77. package/dist/env.js +3152 -0
  78. package/dist/errors-BMFaY68Q.d.ts +33 -0
  79. package/dist/errors-BpWbnbb_.js +13 -0
  80. package/dist/gameplay-Ccruc3Wd.js +1501 -0
  81. package/dist/gameplay.d.ts +543 -0
  82. package/dist/gameplay.js +2 -0
  83. package/dist/heightmap-CroQPEER.js +185 -0
  84. package/dist/index.d.ts +305 -0
  85. package/dist/index.js +62 -0
  86. package/dist/json-BLk7H2Qa.js +30 -0
  87. package/dist/loader-CGs_G-r0.js +919 -0
  88. package/dist/loader-Mo0KghCv.d.ts +41 -0
  89. package/dist/net.d.ts +427 -0
  90. package/dist/net.js +772 -0
  91. package/dist/noise-CGUMx44x.js +82 -0
  92. package/dist/particle-sim-CbN4YUuH.d.ts +63 -0
  93. package/dist/particle-sim-DYuSUxvK.js +1319 -0
  94. package/dist/physics-2d-KuMWPTf6.js +288 -0
  95. package/dist/physics-3d-Dl67vOLT.js +434 -0
  96. package/dist/react.d.ts +65 -0
  97. package/dist/react.js +209 -0
  98. package/dist/register-BuUV1_KB.js +561 -0
  99. package/dist/register-CNlYAS1_.js +10634 -0
  100. package/dist/register-DPEV9_9t.js +851 -0
  101. package/dist/register-Dasmnurl.js +374 -0
  102. package/dist/registry-BVJ2HbCn.js +132 -0
  103. package/dist/rng-DP-SR7eg.js +38 -0
  104. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  105. package/dist/schema-CcoWb32N.d.ts +104 -0
  106. package/dist/test.d.ts +158 -0
  107. package/dist/test.js +275 -0
  108. package/dist/touch-031PxtCR.js +208 -0
  109. package/dist/vite.d.ts +26 -0
  110. package/dist/vite.js +57 -0
  111. package/editor/assets/GameServer-C56iOUgF.js +1 -0
  112. package/editor/assets/agent8-Bp7QFI7v.js +1 -0
  113. package/editor/assets/index-DF3tMeKJ.css +1 -0
  114. package/editor/assets/index-Dl2pjA8e.js +7365 -0
  115. package/editor/assets/rapier-CEuLKeCu.js +1 -0
  116. package/editor/assets/rapier-DE6a0vmv.js +1 -0
  117. package/editor/index.html +169 -0
  118. package/package.json +97 -0
  119. package/schemas/scene.schema.json +4254 -0
  120. package/skills/README.md +9 -0
  121. package/skills/incanto-3d-character.md +229 -0
  122. package/skills/incanto-3d-models.md +151 -0
  123. package/skills/incanto-assets.md +118 -0
  124. package/skills/incanto-audio.md +309 -0
  125. package/skills/incanto-behaviors-and-scripts.md +169 -0
  126. package/skills/incanto-building-2d-games.md +242 -0
  127. package/skills/incanto-building-3d-games.md +245 -0
  128. package/skills/incanto-editor.md +163 -0
  129. package/skills/incanto-environment.md +743 -0
  130. package/skills/incanto-gameplay-behaviors.md +707 -0
  131. package/skills/incanto-multiplayer.md +264 -0
  132. package/skills/incanto-node-reference.md +797 -0
  133. package/skills/incanto-physics-and-input.md +164 -0
  134. package/skills/incanto-scene-json-authoring.md +325 -0
  135. package/skills/incanto-verifying-your-game.md +191 -0
  136. package/skills/incanto-web-integration.md +96 -0
  137. package/templates/agent8-server.js +84 -0
  138. package/templates/agent8-server.ts +138 -0
@@ -0,0 +1,851 @@
1
+ import { a as Rng, c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CcoWb32N.js";
2
+
3
+ //#region src/core/signal.d.ts
4
+ /**
5
+ * Minimal typed observer used for every engine event (Godot signal semantics).
6
+ *
7
+ * Emission is snapshot-based: listeners added during an emit do not fire in that
8
+ * emit, and listeners removed during an emit are skipped.
9
+ */
10
+ type SignalListener<Args extends unknown[]> = (...args: Args) => void;
11
+ declare class Signal<Args extends unknown[] = unknown[]> {
12
+ private connections;
13
+ /** Connect a listener. Returns a disposer. Connecting the same fn twice is a no-op. */
14
+ connect(fn: SignalListener<Args>, opts?: {
15
+ once?: boolean;
16
+ }): () => void;
17
+ disconnect(fn: SignalListener<Args>): void;
18
+ disconnectAll(): void;
19
+ emit(...args: Args): void;
20
+ get connectionCount(): number;
21
+ }
22
+ //#endregion
23
+ //#region src/core/audio/buses.d.ts
24
+ /** The two volume buses every sound routes through (plus the global `master`). */
25
+ type BusName = "sfx" | "music";
26
+ /**
27
+ * Global volume state — `master` × `sfx`/`music` gain (0..1) plus a `muted`
28
+ * flag. PURE state (no WebAudio): games and AI set it to control overall
29
+ * loudness/mute; the renderer reads `effectiveVolume()` when it actually plays
30
+ * a sound. Lives on the engine as `engine.audio` (instance-scoped, no
31
+ * singletons). The WebAudio wiring is in the adapter; this just holds the
32
+ * numbers so they're fully testable in `node`.
33
+ *
34
+ * ```ts
35
+ * engine.audio.master = 0.8; // dim everything
36
+ * engine.audio.music = 0.4; // quieter background music
37
+ * engine.audio.muted = true; // mute toggle
38
+ * ```
39
+ */
40
+ declare class AudioBuses {
41
+ /** Fires whenever any value changes (drives live re-gain of playing sounds). */
42
+ readonly changed: Signal<[]>;
43
+ private _master;
44
+ private _sfx;
45
+ private _music;
46
+ private _muted;
47
+ get master(): number;
48
+ set master(v: number);
49
+ get sfx(): number;
50
+ set sfx(v: number);
51
+ get music(): number;
52
+ set music(v: number);
53
+ get muted(): boolean;
54
+ set muted(v: boolean);
55
+ /** Final gain for a sound on `bus` with its own `sourceVolume` (all clamped). */
56
+ effectiveVolume(bus: BusName, sourceVolume: number): number;
57
+ /** Clamp + finite-guard a new value; emit only on a real change. */
58
+ private assign;
59
+ }
60
+ //#endregion
61
+ //#region src/core/audio/music-manager.d.ts
62
+ /**
63
+ * One streamed music track the manager controls — a thin handle the adapter
64
+ * implements over an HTMLAudio element routed through a WebAudio GainNode (so
65
+ * its gain can ramp). Pure-JS fakes implement the same shape for tests.
66
+ */
67
+ interface MusicTrack {
68
+ readonly src: string;
69
+ /** Set the track's output gain (0..1, already bus-multiplied). */
70
+ setGain(gain: number): void;
71
+ setLoop(loop: boolean): void;
72
+ /** Begin (or resume) playback. May be gesture-blocked; that's not an error. */
73
+ play(): void;
74
+ /** Stop and release the underlying element/source. */
75
+ stop(): void;
76
+ }
77
+ /** Backend that mints {@link MusicTrack}s — WebAudio-backed in the browser. */
78
+ interface MusicBackend {
79
+ /** False headless (no AudioContext) — the manager stays a pure no-op. */
80
+ readonly available?: boolean;
81
+ createTrack(src: string): MusicTrack;
82
+ /** Resume a gesture-suspended context (wired to the first user gesture). */
83
+ unlock(): void;
84
+ }
85
+ interface PlayMusicOptions {
86
+ /** Loop the track (default true — music usually loops). */
87
+ loop?: boolean;
88
+ /** Fade in over N seconds (default 0 — start at full gain). */
89
+ fadeIn?: number;
90
+ /** Which volume bus to route through (default 'music'). */
91
+ bus?: BusName;
92
+ }
93
+ /**
94
+ * Single-track background-music manager: plays ONE music track, crossfading to
95
+ * a new one (equal-power) or fading in/out. Lives on the engine as
96
+ * `engine.music`; routes through `engine.audio` (the music bus by default) so
97
+ * the global volume/mute sliders dim it for free.
98
+ *
99
+ * The state machine (current/outgoing track, fade phase + timer) is fully
100
+ * testable headlessly via an injected backend; the real backend is WebAudio +
101
+ * HTMLAudio and a no-op when there's no AudioContext. Drive `tick(dt)` once per
102
+ * frame to advance fades (the engine wires this to `updated`).
103
+ *
104
+ * ```ts
105
+ * engine.music.play('incanto/assets/audio/theme.mp3'); // loop, full
106
+ * engine.music.crossfadeTo('boss.mp3', 3); // 3s equal-power swap
107
+ * engine.music.stop(2); // fade out over 2s
108
+ * engine.music.setVolume(0.5); // per-manager volume
109
+ * ```
110
+ */
111
+ declare class MusicManager {
112
+ private readonly buses;
113
+ private backend;
114
+ private resolved;
115
+ /** The current (incoming) track; an outgoing one lives during a fade. */
116
+ private active;
117
+ private outgoing;
118
+ private _bus;
119
+ private _volume;
120
+ constructor(buses: AudioBuses);
121
+ /** Source of the logically-current track, or null when nothing is playing. */
122
+ get current(): string | null;
123
+ /** Per-manager volume (0..1), on top of the bus gain. */
124
+ get volume(): number;
125
+ private ensure;
126
+ /** Resume a gesture-suspended context + (re)start any pending track. */
127
+ unlock(): void;
128
+ /** Play a single track (replacing any current one immediately, no fade). */
129
+ play(src: string, opts?: PlayMusicOptions): void;
130
+ /**
131
+ * Equal-power crossfade to a new track over `seconds`. With no current track
132
+ * it's a fade-in. Crossfading to the already-current src is a no-op.
133
+ */
134
+ crossfadeTo(src: string, seconds?: number): void;
135
+ /** Stop the current track, optionally fading out over `fadeOut` seconds. */
136
+ stop(fadeOut?: number): void;
137
+ /** Set the per-manager volume (re-applied to live tracks on the next tick). */
138
+ setVolume(v: number): void;
139
+ /** Advance fades by `dt` seconds and (re)apply bus×fade gains. Frame-driven. */
140
+ tick(dt: number): void;
141
+ /** Effective bus gain for THIS manager (master × bus × manager volume). */
142
+ private busGain;
143
+ /** Push the current fade-derived gains onto both tracks. */
144
+ private applyGains;
145
+ private killOutgoing;
146
+ }
147
+ //#endregion
148
+ //#region src/core/audio/sfx-presets.d.ts
149
+ /**
150
+ * jsfxr/sfxr-style procedural sound parameters — the AUDIO analog of the
151
+ * particle presets: zero asset bytes, instant, deterministic. A small, pure
152
+ * float-DSP synth (`synthSfx`) turns a param set into a PCM `Float32Array`
153
+ * entirely in core (no WebAudio, no DOM), so the params and the waveform are
154
+ * fully unit-testable in `node`. The browser path (webaudio-sfx.ts) just wraps
155
+ * the PCM in an AudioBuffer and plays it.
156
+ *
157
+ * This is intentionally a *small* sfxr — enough for crisp arcade SFX, not a
158
+ * full DAW. Each preset is one oscillator + an ADSR envelope + optional
159
+ * frequency ramp/vibrato/noise, mirroring the classic "Bfxr" knobs.
160
+ */
161
+ type SfxWave = "square" | "sawtooth" | "sine" | "triangle" | "noise";
162
+ interface SfxParams {
163
+ /** Oscillator shape. `noise` is white noise (explosions, hits, steps). */
164
+ wave: SfxWave;
165
+ /** Starting pitch in Hz. */
166
+ baseFreq: number;
167
+ /** Linear pitch slide over the sound, in Hz/second (+ rises, − falls). */
168
+ freqRamp: number;
169
+ /** Attack time (s) — fade in from silence. */
170
+ attack: number;
171
+ /** Sustain time (s) — the body of the sound at full level. */
172
+ sustain: number;
173
+ /** Decay time (s) — fade out to silence. */
174
+ decay: number;
175
+ /** Square-wave duty cycle 0..1 (ignored by other waves). */
176
+ duty?: number;
177
+ /** Vibrato depth as a fraction of baseFreq (0 = none). */
178
+ vibratoDepth?: number;
179
+ /** Vibrato rate in Hz. */
180
+ vibratoRate?: number;
181
+ /** Peak amplitude 0..1. */
182
+ volume: number;
183
+ }
184
+ /**
185
+ * A tasteful, distinct set of common game sounds. Pick one via
186
+ * `AudioPlayer.preset`. Tuned by ear for crisp arcade feel; `seed`/`pitch`
187
+ * props add free variation so repeated sounds don't feel robotic.
188
+ */
189
+ declare const SFX_PRESETS: Record<string, SfxParams>;
190
+ declare const SFX_PRESET_NAMES: readonly string[];
191
+ interface SynthOptions {
192
+ /** Output sample rate (Hz) — match the AudioContext's. Default 44100. */
193
+ sampleRate?: number;
194
+ /** Pitch multiplier for variation (1 = preset's pitch). Default 1. */
195
+ pitch?: number;
196
+ /** Seed for the noise generator + tiny envelope jitter. Default 0. */
197
+ seed?: number;
198
+ }
199
+ /**
200
+ * Render a preset to mono PCM in [-1, 1]. PURE: identical inputs → identical
201
+ * output (the only randomness is the seeded noise generator), so determinism is
202
+ * unit-testable headlessly. Length = ceil((attack+sustain+decay) * sampleRate).
203
+ */
204
+ declare function synthSfx(params: SfxParams, opts?: SynthOptions): Float32Array;
205
+ //#endregion
206
+ //#region src/core/audio/spatial.d.ts
207
+ /**
208
+ * PURE spatial-audio math — the testable heart of 3D positional sound. No
209
+ * WebAudio, no three: just the distance-attenuation curve and listener-relative
210
+ * panning that the adapter feeds into a real `PannerNode`. Mirrors the WebAudio
211
+ * `PannerNode` distance models so the headless math and the browser graph agree,
212
+ * and so the gain we apply on the (non-spatial) HTMLAudio path matches what a
213
+ * panner would produce. Fully unit-testable in `node`.
214
+ */
215
+ type Vec3 = readonly [number, number, number];
216
+ /** The three WebAudio distance models (PannerNode.distanceModel). */
217
+ type RolloffModel = "inverse" | "linear" | "exponential";
218
+ declare const ROLLOFF_MODELS: readonly RolloffModel[];
219
+ interface SpatialParams {
220
+ /** Distance at which gain is 1; closer never gets louder. */
221
+ refDistance: number;
222
+ /** Distance past which gain stops falling (clamped). */
223
+ maxDistance: number;
224
+ /** Attenuation curve shape (matches PannerNode.distanceModel). */
225
+ rolloff: RolloffModel;
226
+ /**
227
+ * Rolloff factor (PannerNode.rolloffFactor) — how quickly gain drops.
228
+ * Defaults to 1. Higher = steeper falloff.
229
+ */
230
+ rolloffFactor?: number;
231
+ }
232
+ /** A listener pose in world space (the active Camera3D drives this). */
233
+ interface Listener {
234
+ position: Vec3;
235
+ /** Unit-ish forward (camera looks down -Z by default). */
236
+ forward: Vec3;
237
+ /** Unit-ish up. */
238
+ up: Vec3;
239
+ }
240
+ /**
241
+ * Gain (0..1) for a source `distance` units from the listener, per the chosen
242
+ * model. Identical to the WebAudio PannerNode formulas so the headless number
243
+ * matches the browser panner:
244
+ *
245
+ * - inverse: ref / (ref + factor·(clamp(d) − ref))
246
+ * - linear: 1 − factor·(clamp(d) − ref) / (max − ref)
247
+ * - exponential: (clamp(d) / ref)^(−factor)
248
+ *
249
+ * where `clamp(d)` is `d` clamped to `[ref, max]`. Always full inside
250
+ * `refDistance`; monotonic non-increasing out to `maxDistance`. Non-finite or
251
+ * degenerate inputs return a safe finite gain.
252
+ */
253
+ declare function spatialGain(distance: number, params: SpatialParams): number;
254
+ /**
255
+ * Stereo pan (−1 left … 0 center … +1 right) for a source at `sourcePos`,
256
+ * relative to the listener's orientation. Projects the listener→source vector
257
+ * onto the listener's RIGHT axis (forward × up) and normalizes by its length —
258
+ * sign tells left/right, magnitude tells how far off-axis. A source at the
259
+ * listener position (or dead ahead) is centered. Result clamped to [−1, 1].
260
+ *
261
+ * This is the CPU twin of what HRTF/equalpower panning does to the azimuth; the
262
+ * real PannerNode does the full spatialization, but exposing the sign here makes
263
+ * the geometry unit-testable and lets the 2D fallback pan by the same rule.
264
+ */
265
+ declare function spatialPan(sourcePos: Vec3, listener: Listener): number;
266
+ //#endregion
267
+ //#region src/core/audio/webaudio-sfx.d.ts
268
+ /** A spatial emitter: where the sound is + where the listener is. */
269
+ interface SpatialPlay {
270
+ /** Emitter world position. */
271
+ position: Vec3;
272
+ /** The listener pose (active Camera3D). */
273
+ listener: Listener;
274
+ refDistance: number;
275
+ maxDistance: number;
276
+ rolloff: RolloffModel;
277
+ rolloffFactor?: number;
278
+ }
279
+ /** True when a real (or injected) AudioContext backend exists. */
280
+ declare function isAudioContextAvailable(): boolean;
281
+ interface SfxPlayOptions {
282
+ pitch?: number;
283
+ seed?: number;
284
+ /** When set, the sound is spatialized through a PannerNode at this emitter. */
285
+ spatial?: SpatialPlay;
286
+ }
287
+ /**
288
+ * One AudioContext + a PCM cache. Instance-scoped (held by the renderer's game
289
+ * instance, not a singleton). `play()` synthesizes (cached) and fires a
290
+ * one-shot source at the given gain.
291
+ */
292
+ declare class SfxEngine {
293
+ private ctx;
294
+ private resolved;
295
+ private readonly pcmCache;
296
+ /** True once a backend is present (lazily created on first use). */
297
+ get available(): boolean;
298
+ private ensure;
299
+ /** Resume a gesture-suspended context (wired to the first user gesture). */
300
+ unlock(): void;
301
+ /**
302
+ * Play a preset at `gain` (0..1, already bus-multiplied by the caller). Each
303
+ * call spawns its own source so rapid repeats overlap instead of cutting off.
304
+ * Headless → no-op.
305
+ */
306
+ play(params: SfxParams, gain: number, opts?: SfxPlayOptions): void;
307
+ }
308
+ //#endregion
309
+ //#region src/core/input.d.ts
310
+ /**
311
+ * Declarative input from scene JSON `input{}` — DOM-free logic (feed key state
312
+ * via `handleKey`, or wire a browser with `attachKeyboard(window)`).
313
+ *
314
+ * Convention: vector2 follows the 2D y-down space (up = -y). `justPressed` /
315
+ * `justReleased` are one-frame edges, settled by the Engine each tick.
316
+ */
317
+ declare class InputMap {
318
+ private readonly actions;
319
+ private readonly down;
320
+ private readonly pressedEdge;
321
+ private readonly releasedEdge;
322
+ private detach;
323
+ /** Load (or extend with) scene-JSON action declarations. Hard-validates shape. */
324
+ declare(decls: Record<string, unknown>): void;
325
+ /** Feed a key state change (code = KeyboardEvent.code, e.g. 'Space', 'KeyW'). */
326
+ handleKey(code: string, isDown: boolean): void;
327
+ private readonly injectedDown;
328
+ private readonly injectedPressed;
329
+ private readonly injectedReleased;
330
+ private readonly injectedVectors;
331
+ /**
332
+ * Press a button ACTION directly — no key codes involved. This is how
333
+ * scripted gameplay tests and touch buttons drive the game by intent
334
+ * (`press('jump')`) instead of reverse-engineering keybinds.
335
+ */
336
+ pressAction(action: string): void;
337
+ /** Release an injected button action (yields one justReleased frame). */
338
+ releaseAction(action: string): void;
339
+ /**
340
+ * Feed an analog direction for a vector2 ACTION — virtual joysticks and
341
+ * scripted runs. Persists until replaced; (0, 0) clears the injection.
342
+ * Combines with key state in getVector (clamped to unit length).
343
+ */
344
+ setActionVector(action: string, x: number, y: number): void;
345
+ /**
346
+ * Actions the scene wants on-screen touch controls for, in declaration
347
+ * order (`"touch": "joystick"` on vector2, `"touch": "button"` on buttons).
348
+ * The touch overlay (core/touch.ts) renders these.
349
+ */
350
+ touchControls(): Array<{
351
+ action: string;
352
+ kind: "joystick" | "button";
353
+ }>;
354
+ /** Drop all injected action state (held buttons, vectors, pending edges). */
355
+ clearInjected(): void;
356
+ private dx;
357
+ private dy;
358
+ private wheel;
359
+ /** Mouse buttons feed the same code space as keys: Mouse0/Mouse1/Mouse2. */
360
+ handleMouseButton(button: number, isDown: boolean): void;
361
+ /** Accumulate look deltas (movementX/Y under pointer lock, else move deltas). */
362
+ handlePointerMove(dx: number, dy: number): void;
363
+ handleWheel(deltaY: number): void;
364
+ /** Drain the accumulated pointer delta (read once per frame). */
365
+ pointerDelta(): {
366
+ x: number;
367
+ y: number;
368
+ };
369
+ /** Drain the accumulated wheel delta. */
370
+ wheelDelta(): number;
371
+ /**
372
+ * Wire browser pointer events on a canvas: buttons → Mouse0/1/2 codes,
373
+ * movement → pointerDelta (movementX/Y so pointer lock just works),
374
+ * wheel → wheelDelta. `lockOnClick` requests pointer lock on mousedown
375
+ * (the FPS pattern).
376
+ */
377
+ attachPointer(target: HTMLElement, opts?: {
378
+ lockOnClick?: boolean;
379
+ }): () => void;
380
+ /**
381
+ * Wire browser keyboard events. Returns (and chains into dispose()) a detach
382
+ * function.
383
+ *
384
+ * By default the browser default is prevented for keys BOUND to a declared
385
+ * action — an embedded game must not scroll its host page on Space/arrows.
386
+ * Keys typed into editable elements (inputs, textareas, contenteditable)
387
+ * are ignored entirely so DOM UI overlays keep working.
388
+ */
389
+ attachKeyboard(target: {
390
+ addEventListener: (t: string, cb: (e: KeyboardEvent) => void) => void;
391
+ removeEventListener: (t: string, cb: (e: KeyboardEvent) => void) => void;
392
+ }, opts?: {
393
+ preventDefault?: "bound" | "none";
394
+ }): () => void;
395
+ /** Whether any declared action binds this key code. */
396
+ private codeIsBound;
397
+ dispose(): void;
398
+ isPressed(action: string): boolean;
399
+ justPressed(action: string): boolean;
400
+ justReleased(action: string): boolean;
401
+ /** Normalized direction for a vector2 action (y-down: up = -y). */
402
+ getVector(action: string): {
403
+ x: number;
404
+ y: number;
405
+ };
406
+ /** Consume one-frame edges. The Engine calls this at the end of every tick. */
407
+ endFrame(): void;
408
+ /**
409
+ * Drop all action declarations and injected action state (physical key
410
+ * state is kept). The Engine calls this on setScene so keybinds never
411
+ * bleed between scenes.
412
+ */
413
+ clear(): void;
414
+ private get;
415
+ private button;
416
+ }
417
+ //#endregion
418
+ //#region src/core/log.d.ts
419
+ type LogLevel = "debug" | "info" | "warn" | "error";
420
+ interface LogEntry {
421
+ /** Monotonic per-manager sequence number (1-based). */
422
+ readonly seq: number;
423
+ /** Wall-clock-ish timestamp (performance.now when available) — diagnostics only. */
424
+ readonly timeMs: number;
425
+ readonly level: LogLevel;
426
+ /** The raw logged values, untouched — consumers format. */
427
+ readonly parts: readonly unknown[];
428
+ }
429
+ /**
430
+ * The engine's log channel (`engine.log`, `this.log` in a Behavior): a ring
431
+ * buffer plus a live `added` signal, so debug overlays and headless test
432
+ * harnesses can tail game logs without scraping the browser console.
433
+ */
434
+ declare class LogManager {
435
+ /** Fires once per entry, after it is buffered. */
436
+ readonly added: Signal<[LogEntry]>;
437
+ private readonly buffer;
438
+ private readonly capacity;
439
+ private seq;
440
+ constructor(capacity?: number);
441
+ debug(...parts: unknown[]): void;
442
+ info(...parts: unknown[]): void;
443
+ warn(...parts: unknown[]): void;
444
+ error(...parts: unknown[]): void;
445
+ /** Buffered entries, oldest first (capped at capacity). */
446
+ entries(): readonly LogEntry[];
447
+ /** Empty the buffer. The sequence keeps counting (entries stay unique). */
448
+ clear(): void;
449
+ private push;
450
+ }
451
+ //#endregion
452
+ //#region src/core/scene-tree.d.ts
453
+ /**
454
+ * Owns a node tree and drives its lifecycle:
455
+ *
456
+ * - `setRoot` → onEnterTree parent-first, then onReady children-first (once per instance)
457
+ * - `update`/`fixedUpdate` → parent-first traversal, then flush of queued frees
458
+ * - group queries across attached nodes
459
+ *
460
+ * Headless by design — tests step it manually; the render loop (M2) calls it.
461
+ */
462
+ declare class SceneTree {
463
+ private _root;
464
+ private _engine;
465
+ private readonly freeQueue;
466
+ private _frameId;
467
+ /**
468
+ * Monotonic update-frame counter — bumped once per `update()`. Per-frame
469
+ * caches (e.g. the 3d grass-bender body gather) key off this so they rebuild
470
+ * at most once a frame regardless of node visitation order.
471
+ */
472
+ get frameId(): number;
473
+ /**
474
+ * @internal Opaque per-frame scratch the 3d layer parks its shared moving-body
475
+ * snapshot on (kept here so it is per-tree-instance, never a module global —
476
+ * core stays three-free, the 3d resolver owns the shape).
477
+ */
478
+ _frameScratch: unknown;
479
+ get root(): Node | null;
480
+ /** The engine driving this tree (set by Engine.setScene), or null. */
481
+ get engine(): Engine | null;
482
+ /** @internal */
483
+ _setEngine(engine: Engine | null): void;
484
+ setRoot(node: Node): void;
485
+ update(dt: number): void;
486
+ fixedUpdate(dt: number): void;
487
+ getNodesInGroup(group: string): Node[];
488
+ /** Call `method(...args)` on every group member that implements it. */
489
+ callGroup(group: string, method: string, ...args: unknown[]): void;
490
+ /** @internal */
491
+ _queueFree(node: Node): void;
492
+ /** @internal Called by Node.free(): a freed root must not be re-drivable. */
493
+ _detachRoot(node: Node): void;
494
+ private flushFreeQueue;
495
+ }
496
+ //#endregion
497
+ //#region src/core/node.d.ts
498
+ /** Lifecycle hooks a SceneTree drives. Wired in scene-tree.ts. */
499
+ interface NodeLifecycle {
500
+ onEnterTree(): void;
501
+ onReady(): void;
502
+ onExitTree(): void;
503
+ update(dt: number): void;
504
+ fixedUpdate(dt: number): void;
505
+ }
506
+ /**
507
+ * Base class of everything in an Incanto scene (Godot's Node model).
508
+ *
509
+ * Pure data + tree structure: no rendering, no DOM, no three.js — renderer
510
+ * adapters subscribe from the outside.
511
+ */
512
+ declare class Node implements NodeLifecycle {
513
+ static readonly typeName: string;
514
+ /**
515
+ * Signals this node type can emit, declared statically (merged up the class
516
+ * hierarchy). A behavior's `static signals` are declared onto its node at
517
+ * load. Emitting or subscribing an UNDECLARED signal is a hard error —
518
+ * a typo'd signal name must fail loudly, never silently never-fire.
519
+ */
520
+ static readonly signals?: readonly string[];
521
+ private _name;
522
+ private _parent;
523
+ private readonly _children;
524
+ private readonly _groups;
525
+ private readonly _signals;
526
+ private _declared;
527
+ private _tree;
528
+ private _ready;
529
+ /**
530
+ * Optional STABLE identifier (scene JSON `uid`) — unlike names (unique only
531
+ * among siblings) a uid is unique across the whole scene, so scripts and
532
+ * tools can address a node no matter where it moves.
533
+ */
534
+ uid: string | null;
535
+ /** Free-form JSON identity for game logic (e.g. `{kind: 'ITEM', value: 10}`). */
536
+ tags: Record<string, unknown>;
537
+ /** Behavior attachment blob from scene JSON (resolved by the loader). */
538
+ script: JsonObject | null;
539
+ /** The resolved behavior instance (set by the loader from `script`). */
540
+ behavior: Behavior | null;
541
+ /** Replication config blob from scene JSON (interpreted in M6; preserved until then). */
542
+ network: JsonObject | null;
543
+ constructor(name?: string);
544
+ get name(): string;
545
+ set name(value: string);
546
+ get parent(): Node | null;
547
+ get children(): readonly Node[];
548
+ get groups(): ReadonlySet<string>;
549
+ /** The SceneTree this node is attached to, or null while detached. */
550
+ get tree(): SceneTree | null;
551
+ /** Whether onReady has run (it runs at most once per instance). */
552
+ get isReady(): boolean;
553
+ addChild<T extends Node>(child: T): T;
554
+ removeChild(child: Node): void;
555
+ reparent(newParent: Node): void;
556
+ findChild(name: string, recursive?: boolean): Node | null;
557
+ /** Topmost ancestor (the node itself when detached). */
558
+ getRoot(): Node;
559
+ /** Depth-first search of THIS subtree for the node carrying `uid`. */
560
+ getNodeByUid(uid: string): Node | null;
561
+ /** Every node in THIS subtree named `name` — names repeat, so a list. */
562
+ getNodesByName(name: string): Node[];
563
+ getPath(): string;
564
+ getNode(path: string): Node;
565
+ getNodeOrNull(path: string): Node | null;
566
+ private resolve;
567
+ addToGroup(group: string): void;
568
+ removeFromGroup(group: string): void;
569
+ isInGroup(group: string): boolean;
570
+ private declaredSignals;
571
+ /** Declare an ad-hoc signal on THIS instance (static `signals` covers types). */
572
+ declareSignal(name: string): void;
573
+ /** Every signal this instance may emit (static + behavior + ad-hoc). */
574
+ declaredSignalNames(): string[];
575
+ private assertDeclared;
576
+ /** Get the named DECLARED signal (creating its Signal object on demand). */
577
+ signal(name: string): Signal<unknown[]>;
578
+ on(signal: string, fn: SignalListener<unknown[]>, opts?: {
579
+ once?: boolean;
580
+ }): () => void;
581
+ off(signal: string, fn: SignalListener<unknown[]>): void;
582
+ emit(signal: string, ...args: unknown[]): void;
583
+ /**
584
+ * Defer destruction to the end of the current update pass (flushed by the
585
+ * SceneTree). Frees immediately when detached from any tree.
586
+ */
587
+ queueFree(): void;
588
+ /** Immediately detach and tear down this node and its children. */
589
+ free(): void;
590
+ /** @internal */
591
+ _propagateEnterTree(tree: SceneTree): void;
592
+ /** @internal */
593
+ _propagateReady(): void;
594
+ /** @internal */
595
+ _propagateExitTree(): void;
596
+ /** @internal */
597
+ _propagateUpdate(dt: number): void;
598
+ /** @internal */
599
+ _propagateFixedUpdate(dt: number): void;
600
+ onEnterTree(): void;
601
+ onReady(): void;
602
+ onExitTree(): void;
603
+ update(_dt: number): void;
604
+ fixedUpdate(_dt: number): void;
605
+ }
606
+ //#endregion
607
+ //#region src/core/scene/scene.d.ts
608
+ /**
609
+ * A loaded, live scene: the node tree plus everything needed to round-trip
610
+ * back to scene JSON (declared connections, asset/input/multiplayer blobs).
611
+ *
612
+ * JSON is the source of truth for STRUCTURE; imperative listeners added via
613
+ * `node.on(...)` are code, not data, and intentionally do not serialize.
614
+ */
615
+ declare class Scene {
616
+ readonly name: string;
617
+ readonly dimension: "2d" | "3d" | undefined;
618
+ readonly root: Node;
619
+ readonly tree: SceneTree;
620
+ /** Scene-level rendering environment (read by renderer adapters). */
621
+ readonly environment: JsonObject | undefined;
622
+ /** Asset declarations (consumed by renderer/asset layers, `$key` references). */
623
+ readonly assets: Record<string, JsonObject> | undefined;
624
+ /** Named constant values (`{"@const": "NAME"}` prop references resolve to these). */
625
+ readonly constants: Record<string, JsonValue> | undefined;
626
+ /** Input action declarations (loaded into `Engine.input` on setScene). */
627
+ readonly input: JsonObject | undefined;
628
+ /** Physics config (gravity etc. — interpreted by the physics modules). */
629
+ readonly physics: JsonObject | undefined;
630
+ /** Multiplayer config (room etc. — interpreted by incanto/net). */
631
+ readonly multiplayer: JsonObject | undefined;
632
+ /** Design-resolution viewport (consumed by renderers via resolveViewport). */
633
+ readonly viewport: JsonObject | undefined;
634
+ private readonly connections;
635
+ constructor(source: SceneJson, root: Node, tree: SceneTree);
636
+ /** Lossless export. Note: expanded sub-scene instances serialize as full trees in M1. */
637
+ toJSON(): SceneJson;
638
+ }
639
+ //#endregion
640
+ //#region src/core/stats.d.ts
641
+ /**
642
+ * Performance-stats shapes — pure data, importable everywhere (core stays
643
+ * three-free; the renderer adapters fill RendererStats from three's
644
+ * `renderer.info`).
645
+ */
646
+ /** Loop-side counters from `engine.stats()` — queryable at any time. */
647
+ interface EngineStats {
648
+ /** Frames per second over the last ~60 REAL ticks (headless runs: 0). */
649
+ fps: number;
650
+ /** Mean frame delta in ms over the same window (headless runs: 0). */
651
+ frameMs: number;
652
+ /** Current node count of the active scene tree (no scene: 0). */
653
+ nodes: number;
654
+ /** Whether the loop is scheduled (start() without stop()/dispose()). */
655
+ running: boolean;
656
+ }
657
+ /** GPU-side counters from `renderer.stats()` — the LAST rendered frame. */
658
+ interface RendererStats {
659
+ triangles: number;
660
+ drawCalls: number;
661
+ geometries: number;
662
+ textures: number;
663
+ }
664
+ /** The merged `game.stats()` surface returned by createGame2D/3D. */
665
+ type GameStats = EngineStats & RendererStats;
666
+ //#endregion
667
+ //#region src/core/engine.d.ts
668
+ /** Schedules a per-frame callback; returns a disposer. */
669
+ type Scheduler = (cb: (nowMs: number) => void) => () => void;
670
+ interface EngineOptions {
671
+ /** Fixed-update frequency in Hz (default 60). */
672
+ fixedHz?: number;
673
+ /** Spiral-of-death clamp: max fixedUpdate steps per tick (default 5). */
674
+ maxFixedStepsPerTick?: number;
675
+ /** Frame source (default: requestAnimationFrame loop). Inject for headless tests. */
676
+ scheduler?: Scheduler;
677
+ /** Seed for `engine.rng` — set it to make a run reproducible (default: random). */
678
+ seed?: number;
679
+ }
680
+ /**
681
+ * The game loop: drives a Scene's tree with fixed-timestep `fixedUpdate`
682
+ * (physics/network window) and variable `update` (everything else).
683
+ *
684
+ * Instance-scoped by design — multiple engines can coexist. Headless-testable
685
+ * via the injectable scheduler and the public `tick(nowMs)`.
686
+ */
687
+ declare class Engine {
688
+ /** Emitted after the tree's variable update each frame, with dt seconds. */
689
+ readonly updated: Signal<[number]>;
690
+ /** Emitted after each fixed step, with the fixed dt seconds. */
691
+ readonly fixedUpdated: Signal<[number]>;
692
+ /**
693
+ * Emitted after a scene swap completes (input map redeclared) with the new
694
+ * scene, and with null on dispose — overlays (touch controls, debug panels)
695
+ * rebuild themselves here.
696
+ */
697
+ readonly sceneChanged: Signal<[Scene | null]>;
698
+ /** Declarative input — scene `input{}` declarations load on setScene. */
699
+ readonly input: InputMap;
700
+ /** Seeded randomness for game logic (deterministic when `seed` is set). */
701
+ readonly rng: Rng;
702
+ /** The engine log channel (debug overlay + headless harness tail this). */
703
+ readonly log: LogManager;
704
+ /** Global volume buses — `master` × `sfx`/`music` gain + `muted`. AudioPlayer
705
+ * routes its volume through this; games set it for global volume/mute. */
706
+ readonly audio: AudioBuses;
707
+ /** Low-latency procedural-SFX player (WebAudio, headless-safe). AudioPlayer
708
+ * presets play through it; games may call `engine.sfx.play(...)` directly. */
709
+ readonly sfx: SfxEngine;
710
+ /** Single-track background-music manager (crossfade/loop, headless-safe).
711
+ * `engine.music.play(src)` / `crossfadeTo(src, secs)` / `stop(fadeOut)`;
712
+ * routes through the music bus and is advanced each frame by the loop. */
713
+ readonly music: MusicManager;
714
+ private readonly fixedStep;
715
+ private readonly maxFixedSteps;
716
+ private readonly scheduler;
717
+ private _scene;
718
+ private lastMs;
719
+ private accumulator;
720
+ private disposeScheduler;
721
+ private readonly frameStats;
722
+ constructor(opts?: EngineOptions);
723
+ get scene(): Scene | null;
724
+ /** Replace the active scene. The previous scene's root is freed. */
725
+ setScene(scene: Scene): void;
726
+ start(): void;
727
+ stop(): void;
728
+ /**
729
+ * Live performance counters, queryable at ANY time. fps/frameMs come from a
730
+ * rolling window of REAL `tick` timestamps — headless `step()` runs report 0.
731
+ * Node count walks the active tree on demand. Renderer counters (triangles,
732
+ * draw calls) live on `renderer.stats()` / the merged `game.stats()`.
733
+ */
734
+ stats(): EngineStats;
735
+ /**
736
+ * Render interpolation factor in [0,1]: how far the wall clock has advanced
737
+ * INTO the next fixed step. Renderers lerp physics bodies between their last
738
+ * two fixed-step transforms by this much so motion looks smooth even when the
739
+ * display refresh doesn't divide evenly into the 60Hz fixed step (the classic
740
+ * fixed-timestep judder). Only meaningful in the real-time `tick()` loop;
741
+ * the headless `step()` path doesn't bank wall-clock time.
742
+ */
743
+ get interpolationAlpha(): number;
744
+ /**
745
+ * Full teardown in one call: stop the loop, free the scene tree, detach
746
+ * every input listener. The single-unmount story for SPA embedding —
747
+ * renderers own GPU resources and keep their own dispose().
748
+ */
749
+ dispose(): void;
750
+ /**
751
+ * Advance exactly ONE fixed step and one variable update (both dt = the
752
+ * fixed step), bypassing the wall-clock accumulator entirely. Drift-free
753
+ * by construction — the unit of time for headless harnesses (incanto/test
754
+ * runScript): every input edge is visible to BOTH fixedUpdate and update
755
+ * exactly once.
756
+ */
757
+ step(): void;
758
+ /** Advance the loop manually. First call after (re)start only primes the clock. */
759
+ tick(nowMs: number): void;
760
+ }
761
+ //#endregion
762
+ //#region src/core/registry.d.ts
763
+ /** A node prop definition. The default both documents and types the prop. */
764
+ interface PropDef {
765
+ default: JsonValue;
766
+ /** For enum-like string props: the valid values. Drives editor/debug
767
+ * dropdowns and the generated JSON-Schema enum — keep it exhaustive. */
768
+ options?: readonly string[];
769
+ }
770
+ type PropSchema = Record<string, PropDef>;
771
+ interface NodeCtor {
772
+ new (name?: string): Node;
773
+ readonly typeName: string;
774
+ readonly props?: PropSchema;
775
+ readonly signals?: readonly string[];
776
+ }
777
+ declare function registerNode(ctor: NodeCtor, opts?: {
778
+ replace?: boolean;
779
+ }): void;
780
+ declare function getNodeType(typeName: string): NodeCtor;
781
+ declare function registeredTypes(): string[];
782
+ /** Test isolation helper. */
783
+ declare function clearRegistry(): void;
784
+ /**
785
+ * Effective prop schema for a type: own static `props` merged over every
786
+ * ancestor's (subclass keys win).
787
+ */
788
+ declare function getNodeSchema(typeName: string): PropSchema;
789
+ /** Walk a constructor's prototype chain collecting static `signals` (deduped). */
790
+ declare function mergeStaticSignals(ctor: {
791
+ signals?: readonly string[];
792
+ } | null): string[];
793
+ /** Every signal a registered type declares (its own + inherited). */
794
+ declare function getNodeSignals(typeName: string): string[];
795
+ /**
796
+ * Instantiate a registered type, assign schema defaults (cloned), then the
797
+ * given props — validating every key and its JSON kind against the default.
798
+ */
799
+ declare function createNode(typeName: string, props?: Record<string, JsonValue>): Node;
800
+ //#endregion
801
+ //#region src/core/behavior.d.ts
802
+ interface BehaviorCtor {
803
+ new (): Behavior;
804
+ props?: PropSchema;
805
+ signals?: readonly string[];
806
+ }
807
+ /**
808
+ * Vibe-coded logic attached to a JSON-declared node — the ONE script a node
809
+ * may carry (`"script": {"name": "PlayerController", "props": {...}}`).
810
+ *
811
+ * Lifecycle hooks run AFTER the node's own. Props follow the same
812
+ * schema/defaults/delta model as node props.
813
+ */
814
+ declare abstract class Behavior {
815
+ static props?: PropSchema;
816
+ /**
817
+ * Custom signals this behavior emits via `this.emit(...)` — declared onto
818
+ * its node at load. Undeclared emits are hard errors (typo safety).
819
+ */
820
+ static signals?: readonly string[];
821
+ /** The node this behavior is attached to (assigned by the loader). */
822
+ node: Node;
823
+ /** The running engine, reached through the scene tree. */
824
+ get engine(): Engine;
825
+ /** Shortcut for `this.engine.input`. */
826
+ get input(): InputMap;
827
+ /** Seeded engine randomness — use this, not Math.random(), for replayability. */
828
+ get rng(): Rng;
829
+ /** The engine log channel (visible in the debug overlay and test harness). */
830
+ get log(): LogManager;
831
+ getNode(path: string): Node;
832
+ emit(signal: string, ...args: unknown[]): void;
833
+ on(signal: string, fn: SignalListener<unknown[]>, opts?: {
834
+ once?: boolean;
835
+ }): () => void;
836
+ onEnterTree?(): void;
837
+ onReady?(): void;
838
+ onExitTree?(): void;
839
+ update?(dt: number): void;
840
+ fixedUpdate?(dt: number): void;
841
+ }
842
+ /** Explicit registration — never an import side effect (tree-shaking safety). */
843
+ declare function registerBehavior(name: string, ctor: BehaviorCtor, opts?: {
844
+ replace?: boolean;
845
+ }): void;
846
+ declare function getBehavior(name: string): BehaviorCtor;
847
+ declare function registeredBehaviors(): string[];
848
+ /** Test isolation helper. */
849
+ declare function clearBehaviors(): void;
850
+ //#endregion
851
+ export { BusName as $, LogManager as A, spatialGain as B, RendererStats as C, SceneTree as D, NodeLifecycle as E, Listener as F, SfxWave as G, SFX_PRESETS as H, ROLLOFF_MODELS as I, MusicBackend as J, SynthOptions as K, RolloffModel as L, SfxEngine as M, SfxPlayOptions as N, LogEntry as O, isAudioContextAvailable as P, AudioBuses as Q, SpatialParams as R, GameStats as S, Node as T, SFX_PRESET_NAMES as U, spatialPan as V, SfxParams as W, MusicTrack as X, MusicManager as Y, PlayMusicOptions as Z, registeredTypes as _, registerBehavior as a, Scheduler as b, PropDef as c, createNode as d, Signal as et, getNodeSchema as f, registerNode as g, mergeStaticSignals as h, getBehavior as i, InputMap as j, LogLevel as k, PropSchema as l, getNodeType as m, BehaviorCtor as n, registeredBehaviors as o, getNodeSignals as p, synthSfx as q, clearBehaviors as r, NodeCtor as s, Behavior as t, SignalListener as tt, clearRegistry as u, Engine as v, Scene as w, EngineStats as x, EngineOptions as y, Vec3 as z };