incanto 0.49.0 → 0.51.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 (48) hide show
  1. package/bin/incanto-play.mjs +42 -17
  2. package/dist/2d.d.ts +3 -2
  3. package/dist/2d.js +3 -3
  4. package/dist/3d.d.ts +4 -3
  5. package/dist/3d.js +4 -4
  6. package/dist/{behavior-62q0HWBO.d.ts → behavior-rZNfzVbH.d.ts} +37 -3
  7. package/dist/{create-game-DFBjMetZ.js → create-game-BNaOC3Px.js} +5 -5
  8. package/dist/{create-game-BgV6UbVA.js → create-game-CkzKZ4v5.js} +5 -5
  9. package/dist/debug.d.ts +1 -1
  10. package/dist/{duplicate-CI9WF_bg.js → duplicate-EybyYeyL.js} +1 -1
  11. package/dist/{environment-presets-CZOH5TY5.js → environment-presets-C08pOC6H.js} +2 -2
  12. package/dist/{gameplay-02Btmmjn.js → gameplay-bStgtZBV.js} +175 -6
  13. package/dist/gameplay.d.ts +79 -2
  14. package/dist/gameplay.js +2 -2
  15. package/dist/index.d.ts +14 -5
  16. package/dist/index.js +6 -6
  17. package/dist/{loader-DwazzlQb.js → loader-B2asghWa.js} +350 -1
  18. package/dist/{loader-CeyU_bm1.d.ts → loader-Dkbn56KC.d.ts} +1 -1
  19. package/dist/net.d.ts +1 -1
  20. package/dist/net.js +3 -3
  21. package/dist/{pathfinding-C49JSNNq.d.ts → pathfinding-Bz34pvQD.d.ts} +1 -1
  22. package/dist/{physics-2d-vyCBfACH.js → physics-2d-Ccq2L9R0.js} +8 -3
  23. package/dist/{physics-3d-DpRqw8Mz.js → physics-3d-B2c5KNYh.js} +13 -8
  24. package/dist/react.d.ts +1 -1
  25. package/dist/react.js +1 -1
  26. package/dist/{register-BNPZYJmd.js → register-B_BaaGx-.js} +2 -2
  27. package/dist/{register-uvaZj1KX.js → register-CGq-Hee8.js} +19 -265
  28. package/dist/{register-CB11yp21.js → register-CLVhzWcI.js} +2 -2
  29. package/dist/{replay-C0XJIsO7.js → replay-BgKxGcXH.js} +42 -3
  30. package/dist/{replay-CAphXMyM.d.ts → replay-DIP2_as4.d.ts} +6 -2
  31. package/dist/{src-DF4gCsqO.js → src-C3UwzYXl.js} +1 -1
  32. package/dist/{test-DRna_BQU.js → test-D2gRpk5V.js} +48 -21
  33. package/dist/test.d.ts +3 -3
  34. package/dist/test.js +2 -2
  35. package/dist/vite.js +2 -2
  36. package/editor/assets/{agent8-DCW4TgDt.js → agent8-DbX_msaO.js} +1 -1
  37. package/editor/assets/{debug-RC6qts6S.js → debug-C-kMxdl1.js} +1 -1
  38. package/editor/assets/{index-5dEIhvsf.js → index-CUc1U7wm.js} +91 -91
  39. package/editor/index.html +1 -1
  40. package/package.json +1 -1
  41. package/skills/incanto-building-2d-games.md +6 -1
  42. package/skills/incanto-gameplay-behaviors.md +11 -0
  43. package/skills/incanto-node-reference.md +13 -0
  44. package/skills/incanto-playtesting.md +13 -2
  45. package/skills/incanto-save-slots.md +134 -12
  46. package/templates-app/beacon-isle-3d/package.json +1 -1
  47. package/templates-app/tps-3d/package.json +1 -1
  48. package/templates-app/village-quest-3d/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
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";
1
+ import { $ as T_PREFIX, A as SettingsValues, At as LogEntry, B as captureBehaviors, C as EngineStats, Ct as MusicTrack, Dt as Node, E as DeviceHints, Et as BusName, F as BehaviorState, G as ORDER_GROUP_BASE, H as savesWithoutUid, I as RestoreReport, J as effectiveOrder, K as OrderGroup, L as SaveSlot, M as readDeviceHints, Mt as LogManager, N as suggestQuality, Nt as Signal, O as QualityTier, Ot as NodeLifecycle, P as Scene, Pt as SignalListener, Q as Localization, R as SaveSlots, S as Scheduler, St as MusicManager, T as RendererStats, Tt as AudioBuses, U as SaveStore, V as restoreBehaviors, W as createSaveStore, X as BASE_LOCALE, Y as resolveOrderGroups, Z as LocaleTables, _ as mergeStaticSignals, _t as SfxParams, a as clearBehaviors, at as isAudioContextAvailable, b as Engine, bt as synthSfx, c as registeredBehaviors, ct as Listener, d as PropSchema, dt as SpatialParams, et as suggestLocale, f as clearRegistry, ft as Vec3, g as getNodeType, gt as SFX_PRESET_NAMES, h as getNodeSignals, ht as SFX_PRESETS, i as behaviorSignals, it as SfxPlayOptions, j as qualityEnvironment, jt as LogLevel, k as Settings, kt as SceneTree, l as NodeCtor, lt as ROLLOFF_MODELS, m as getNodeSchema, mt as spatialPan, n as BehaviorCtor, nt as InputMap, o as getBehavior, ot as Voice, p as createNode, pt as spatialGain, q as OrderGroupTable, r as behaviorSchema, rt as SfxEngine, s as registerBehavior, st as VoicePreset, t as Behavior, tt as translationKey, u as PropDef, ut as RolloffModel, v as registerNode, vt as SfxWave, w as GameStats, wt as PlayMusicOptions, x as EngineOptions, xt as MusicBackend, y as registeredTypes, yt as SynthOptions, z as behaviorsWithoutSave } from "./behavior-rZNfzVbH.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-CeyU_bm1.js";
3
+ import { n as loadScene, t as LoadSceneOptions } from "./loader-Dkbn56KC.js";
4
4
  import { i as resolveFrames, n as AnimationEntry, r as resolveAnimation, t as AnimationDef } from "./sprite-animation-CMr6f1K2.js";
5
5
  import { n as ParticleSimConfig, r as ParticleView, t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
6
- import { a as AudioElementLike, i as gridFromRows, n as PathGrid, o as AudioPlayer, r as findPath, t as FindPathOptions } from "./pathfinding-C49JSNNq.js";
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";
6
+ import { a as AudioElementLike, i as gridFromRows, n as PathGrid, o as AudioPlayer, r as findPath, t as FindPathOptions } from "./pathfinding-Bz34pvQD.js";
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-DIP2_as4.js";
8
8
 
9
9
  //#region src/core/audio/crossfade.d.ts
10
10
  /**
@@ -258,6 +258,15 @@ declare class HudLayer extends Node {
258
258
  }
259
259
  /** Shared plumbing: mount into the parent HudLayer's anchor slot. */
260
260
  declare abstract class HudWidgetBase extends Node {
261
+ /**
262
+ * Wireable visibility: `noSave → Continue.hide`.
263
+ *
264
+ * `visible` is a prop, and a `connections[]` handler has to be a METHOD — the
265
+ * same wall that kept a score off the screen until widgets grew `setText`. A
266
+ * title screen greying out its own Continue button is the case that asked.
267
+ */
268
+ show(..._args: unknown[]): void;
269
+ hide(): void;
261
270
  static readonly props: PropSchema;
262
271
  static readonly signals: readonly string[];
263
272
  anchor: HudAnchor;
@@ -848,4 +857,4 @@ declare function computeViewport(canvasW: number, canvasH: number, viewport: {
848
857
  /** Engine version. Kept in sync with package.json by the release pipeline. */
849
858
  declare const VERSION: string;
850
859
  //#endregion
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 };
860
+ 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, savesWithoutUid, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
package/dist/index.js CHANGED
@@ -1,14 +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-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";
1
+ import { A as registerBehavior, C as InputMap, D as behaviorSignals, E as behaviorSchema, M as Signal, O as clearBehaviors, S as resolveOrderGroups, T as Behavior, _ as restoreBehaviors, a as SCENE_FORMAT, b as ORDER_GROUP_BASE, c as SceneTree, d as resolveConstants, f as Node, g as captureBehaviors, h as behaviorsWithoutSave, i as serializeNode, j as registeredBehaviors, k as getBehavior, l as CONST_REF_KEY, m as SaveSlots, n as loadScene, o as computeViewport, p as parseNodePath, r as Scene, s as resolveViewport, u as isConstRef, v as savesWithoutUid, x as effectiveOrder, y as createSaveStore } from "./loader-B2asghWa.js";
2
+ import { A as ROLLOFF_MODELS, B as AudioBuses, C as BASE_LOCALE, D as translationKey, E as suggestLocale, F as synthSfx, I as MusicManager, L as WebAudioMusicBackend, M as spatialPan, N as SFX_PRESETS, O as SfxEngine, P as SFX_PRESET_NAMES, R as crossfadeGains, S as LogManager, T as T_PREFIX, 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 spatialGain, k as isAudioContextAvailable, 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 Localization, x as suggestQuality, z as fadeGain } from "./register-CGq-Hee8.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-C0XJIsO7.js";
5
+ import { n as startRecording, r as auditScene, t as replay } from "./replay-BgKxGcXH.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 { n as logText, r as parseDrive, t as logReport } from "./log-report-lxrQY9cH.js";
9
9
  import { t as createNoise2D } from "./noise-CGUMx44x.js";
10
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
+ import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-C3UwzYXl.js";
12
12
  import { i as resolveRendering, n as attachTouchControls, r as joystickVector, t as TouchControls } from "./touch-BoNg_MnF.js";
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 };
13
+ import { t as duplicateNode } from "./duplicate-EybyYeyL.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, savesWithoutUid, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
@@ -640,6 +640,345 @@ function effectiveOrder(group, renderOrder, table = ORDER_GROUP_BASE) {
640
640
  return (table[group] ?? 0) + renderOrder;
641
641
  }
642
642
  //#endregion
643
+ //#region src/core/save.ts
644
+ const memoryStores = /* @__PURE__ */ new Map();
645
+ function createSaveStore(namespace) {
646
+ const prefix = `incanto:${namespace}:`;
647
+ const local = storageOrNull();
648
+ if (!local) {
649
+ let mem = memoryStores.get(namespace);
650
+ if (!mem) {
651
+ mem = /* @__PURE__ */ new Map();
652
+ memoryStores.set(namespace, mem);
653
+ }
654
+ const backing = mem;
655
+ return {
656
+ get: (key, fallback) => parse(backing.get(key), fallback),
657
+ set: (key, value) => void backing.set(key, JSON.stringify(value)),
658
+ remove: (key) => void backing.delete(key),
659
+ clear: () => backing.clear()
660
+ };
661
+ }
662
+ return {
663
+ get: (key, fallback) => parse(local.getItem(prefix + key) ?? void 0, fallback),
664
+ set: (key, value) => local.setItem(prefix + key, JSON.stringify(value)),
665
+ remove: (key) => local.removeItem(prefix + key),
666
+ clear: () => {
667
+ const doomed = [];
668
+ for (let i = 0; i < local.length; i++) {
669
+ const k = local.key(i);
670
+ if (k?.startsWith(prefix)) doomed.push(k);
671
+ }
672
+ for (const k of doomed) local.removeItem(k);
673
+ }
674
+ };
675
+ }
676
+ function parse(raw, fallback) {
677
+ if (raw === void 0 || raw === null) return fallback;
678
+ try {
679
+ return JSON.parse(raw);
680
+ } catch {
681
+ return fallback;
682
+ }
683
+ }
684
+ function storageOrNull() {
685
+ try {
686
+ if (typeof localStorage === "undefined") return null;
687
+ const probe = "__incanto_probe__";
688
+ localStorage.setItem(probe, "1");
689
+ localStorage.removeItem(probe);
690
+ return localStorage;
691
+ } catch {
692
+ return null;
693
+ }
694
+ }
695
+ //#endregion
696
+ //#region src/core/save-slots.ts
697
+ /**
698
+ * Save slots — "continue where you left off", which no game on this engine could
699
+ * do.
700
+ *
701
+ * `createSaveStore` has been here a long time and `Scene.toJSON()` round-trips a
702
+ * live tree, so two thirds of the work existed. The missing third was that
703
+ * BEHAVIOR state had nowhere to go: `Behavior` declared `onEnterTree`, `onReady`,
704
+ * `onExitTree`, `update` and `fixedUpdate` and nothing for "write yourself down",
705
+ * so `Health.current`, `ScoreKeeper.score` and every quest flag were
706
+ * unrecoverable. Both quest templates this repo ships were RPGs you could not
707
+ * resume.
708
+ *
709
+ * ## What a save is, and what it deliberately is NOT
710
+ *
711
+ * A save is **which scene, plus every behavior's state, keyed by node uid**. It
712
+ * is not a snapshot of the live tree.
713
+ *
714
+ * That is a design decision, not a shortcut. Restoring a live tree by walking
715
+ * paths breaks on this engine specifically:
716
+ *
717
+ * - `Spawner.onReady` DETACHES its prefab template from the tree (see
718
+ * `SpawnSource.resolveTemplate`), so a captured tree and a freshly booted one
719
+ * legitimately disagree about which nodes exist, every time.
720
+ * Every scene with a spawner would report phantom removals.
721
+ * - A spawned enemy carrying its own spawner has already lost ITS template, so
722
+ * re-adding that subtree runs `onReady` against a node that is not there and
723
+ * throws — and `onReady` is not quarantined, so it kills the whole load.
724
+ * - Prop deltas cannot be applied with `applySchemaProps`, which resets every
725
+ * prop to its default before writing.
726
+ *
727
+ * Reloading the scene from source sidesteps all three: the structure comes from
728
+ * the file (which is authoritative and already validated), and the save carries
729
+ * only what the file cannot know. A fresh boot detaches the same templates the
730
+ * captured one did, so there is nothing to reconcile.
731
+ *
732
+ * The cost, stated plainly so nobody discovers it: **spawned enemies and
733
+ * mid-level positions are not restored.** You resume at the scene's start with
734
+ * your stats, inventory, unlocks and quest flags intact. That is what a
735
+ * checkpoint save is, and it is what both quest templates need. A game that
736
+ * wants a position saves it — `serialize()` can return anything.
737
+ *
738
+ * Node uids are the join key because they are the one identifier the engine
739
+ * already promises survives a rename or a reparent.
740
+ */
741
+ /**
742
+ * The one key in a save that is not a uid: authored nodes the run consumed.
743
+ *
744
+ * A save reloads the scene from its FILE, so every collectible comes back —
745
+ * resume a collect-five-to-win run at four and there are five gems on the map
746
+ * again with your four still banked. No behavior can fix that from the inside:
747
+ * the node that knew is the node that was freed.
748
+ *
749
+ * The engine can answer it without anyone's help. A uid in the scene file that
750
+ * is not in the live tree is a node this run consumed. Spawned clones never
751
+ * carry uids (`duplicateNode` drops them so a template can never mint colliding
752
+ * ids), so the ledger is exactly the authored world — the part the file
753
+ * rebuilds. `n_` prefixes every uid, so `#` can never collide with one.
754
+ */
755
+ const FREED_KEY = "#freed";
756
+ /**
757
+ * Every behavior in the tree that has something to say, by uid.
758
+ *
759
+ * A behavior with no `serialize` contributes nothing — the hook is optional in
760
+ * exactly the way the other five are, so adding save support to a game is
761
+ * additive and a game that never saves pays nothing.
762
+ *
763
+ * A node with no `uid` is skipped and reported, because state keyed by nothing
764
+ * cannot be given back. The editor assigns a uid to every node it touches; a
765
+ * hand-written scene may not have.
766
+ */
767
+ function captureBehaviors(root, source) {
768
+ const state = {};
769
+ const unaddressable = [];
770
+ let saveable = 0;
771
+ const walk = (node) => {
772
+ const behavior = node.behavior;
773
+ if (behavior && typeof behavior.serialize === "function") {
774
+ const value = behavior.serialize();
775
+ if (value !== void 0) {
776
+ saveable += 1;
777
+ if (node.uid) state[node.uid] = value;
778
+ else unaddressable.push(node.getPath());
779
+ }
780
+ }
781
+ for (const child of node.children) walk(child);
782
+ };
783
+ walk(root);
784
+ if (source !== void 0) {
785
+ const alive = /* @__PURE__ */ new Set();
786
+ const mark = (node) => {
787
+ const leaving = node.tree?._isQueuedFree(node) ?? false;
788
+ if (node.uid && !leaving) alive.add(node.uid);
789
+ for (const child of node.children) mark(child);
790
+ };
791
+ mark(root);
792
+ const freed = authoredUids(source).filter((uid) => !alive.has(uid));
793
+ if (freed.length > 0) state[FREED_KEY] = freed;
794
+ }
795
+ return {
796
+ state,
797
+ unaddressable,
798
+ saveable
799
+ };
800
+ }
801
+ /** Every uid the scene FILE declares, in document order. */
802
+ function authoredUids(source) {
803
+ const out = [];
804
+ const walk = (node) => {
805
+ if (typeof node !== "object" || node === null) return;
806
+ const n = node;
807
+ if (typeof n.uid === "string" && n.uid !== "") out.push(n.uid);
808
+ if (Array.isArray(n.children)) for (const child of n.children) walk(child);
809
+ };
810
+ walk(source.root);
811
+ return out;
812
+ }
813
+ /**
814
+ * Hand each behavior its state back.
815
+ *
816
+ * Call this AFTER the scene has loaded and `onReady` has run: `onReady` is where
817
+ * a behavior sets its starting values, so restoring first would be overwritten
818
+ * by the fresh start.
819
+ *
820
+ * Never throws on a mismatch. A save from an older build of the game will name
821
+ * uids that no longer exist, and refusing to load it would mean a patch that
822
+ * moves one node deletes everyone's progress. It reports instead.
823
+ */
824
+ function restoreBehaviors(root, state) {
825
+ const report = {
826
+ missing: [],
827
+ skipped: [],
828
+ restored: 0,
829
+ expected: captureBehaviors(root).saveable,
830
+ freed: 0
831
+ };
832
+ for (const [uid, value] of Object.entries(state)) {
833
+ if (uid === "#freed") {
834
+ for (const gone of value ?? []) {
835
+ const node = root.getNodeByUid(gone);
836
+ if (node) {
837
+ node.queueFree();
838
+ report.freed += 1;
839
+ }
840
+ }
841
+ continue;
842
+ }
843
+ const node = root.getNodeByUid(uid);
844
+ if (!node) {
845
+ report.missing.push(uid);
846
+ continue;
847
+ }
848
+ const behavior = node.behavior;
849
+ if (!behavior || typeof behavior.deserialize !== "function") {
850
+ report.skipped.push(uid);
851
+ continue;
852
+ }
853
+ try {
854
+ behavior.deserialize(value);
855
+ report.restored += 1;
856
+ } catch {
857
+ report.skipped.push(uid);
858
+ }
859
+ }
860
+ return report;
861
+ }
862
+ /** Slot ids, so a "3 save slots" menu is a list and not a naming convention. */
863
+ const INDEX_KEY = "slots";
864
+ /**
865
+ * The slot layer: a named list of saves over the existing store.
866
+ *
867
+ * Slot ids are yours (`'auto'`, `'1'`, `'2'`, `'3'`) — the engine does not
868
+ * decide how many you have or whether one of them autosaves.
869
+ */
870
+ var SaveSlots = class {
871
+ store;
872
+ constructor(namespace = "saves", store) {
873
+ this.store = store ?? createSaveStore(namespace);
874
+ }
875
+ /** Slot ids that have a save, newest first. */
876
+ list() {
877
+ const rows = this.store.get(INDEX_KEY, []).map((id) => ({
878
+ id,
879
+ slot: this.read(id)
880
+ })).filter((row) => row.slot !== null);
881
+ rows.sort((a, b) => b.slot.savedAt - a.slot.savedAt);
882
+ return rows.map((row) => row.id);
883
+ }
884
+ /** Every slot with its contents — what a load menu actually renders. */
885
+ all() {
886
+ return this.list().map((id) => ({
887
+ id,
888
+ ...this.read(id)
889
+ }));
890
+ }
891
+ read(id) {
892
+ const raw = this.store.get(key(id), null);
893
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
894
+ const slot = raw;
895
+ if (typeof slot.scene !== "string" || typeof slot.state !== "object" || slot.state === null) return null;
896
+ return {
897
+ scene: slot.scene,
898
+ state: slot.state,
899
+ label: typeof slot.label === "string" ? slot.label : "",
900
+ savedAt: typeof slot.savedAt === "number" ? slot.savedAt : 0,
901
+ playtime: typeof slot.playtime === "number" ? slot.playtime : 0,
902
+ data: slot.data ?? {}
903
+ };
904
+ }
905
+ /**
906
+ * Write a slot.
907
+ *
908
+ * `savedAt` is a parameter rather than `Date.now()` so a test can assert an
909
+ * ordering without sleeping, and so a game that wants server time can use it.
910
+ */
911
+ write(id, slot) {
912
+ const full = {
913
+ scene: slot.scene,
914
+ state: slot.state,
915
+ label: slot.label ?? "",
916
+ savedAt: slot.savedAt ?? 0,
917
+ playtime: slot.playtime ?? 0,
918
+ data: slot.data ?? {}
919
+ };
920
+ this.store.set(key(id), full);
921
+ const ids = this.store.get(INDEX_KEY, []);
922
+ if (!ids.includes(id)) this.store.set(INDEX_KEY, [...ids, id]);
923
+ }
924
+ remove(id) {
925
+ this.store.remove(key(id));
926
+ this.store.set(INDEX_KEY, this.store.get(INDEX_KEY, []).filter((other) => other !== id));
927
+ }
928
+ /** Wipe every slot — a "delete all data" button, and test isolation. */
929
+ clear() {
930
+ for (const id of this.store.get(INDEX_KEY, [])) this.store.remove(key(id));
931
+ this.store.set(INDEX_KEY, []);
932
+ }
933
+ };
934
+ function key(id) {
935
+ return `slot:${id}`;
936
+ }
937
+ /**
938
+ * Behaviors in this tree that hold state and cannot save it — the audit's
939
+ * question, answerable before a player loses an hour.
940
+ *
941
+ * A behavior with props but no `serialize` is not necessarily wrong (an
942
+ * `Oscillate` derives everything from time), so this reports rather than warns,
943
+ * and the caller decides.
944
+ */
945
+ function behaviorsWithoutSave(root) {
946
+ const out = [];
947
+ const walk = (node) => {
948
+ const behavior = node.behavior;
949
+ const name = node.script?.name;
950
+ if (behavior && typeof name === "string" && typeof behavior.serialize !== "function") {
951
+ if (Object.keys(behaviorSchema(name)).length > 0) out.push(`${node.getPath()} (${name})`);
952
+ }
953
+ for (const child of node.children) walk(child);
954
+ };
955
+ walk(root);
956
+ return out;
957
+ }
958
+ /**
959
+ * Behaviors that DO save, on nodes with no uid to save them under — the state
960
+ * that goes nowhere.
961
+ *
962
+ * `incanto-check` warns about the built-ins it can recognise from the JSON
963
+ * (Health, ScoreKeeper, Collector), but a scene file cannot be asked whether
964
+ * YOUR behavior has a `serialize`. This can: it walks the live tree, so a quest
965
+ * log or a wallet of your own is named too.
966
+ *
967
+ * The pair to read before shipping: `behaviorsWithoutSave` is "did you forget
968
+ * to write serialize", this is "did you forget the uid that makes it count".
969
+ */
970
+ function savesWithoutUid(root) {
971
+ const out = [];
972
+ const walk = (node) => {
973
+ const behavior = node.behavior;
974
+ const name = node.script?.name;
975
+ if (behavior && typeof behavior.serialize === "function" && !node.uid) out.push(`${node.getPath()} (${name ?? "behavior"})`);
976
+ for (const child of node.children) walk(child);
977
+ };
978
+ walk(root);
979
+ return out;
980
+ }
981
+ //#endregion
643
982
  //#region src/core/node-path.ts
644
983
  function parseNodePath(path) {
645
984
  if (path === "") throw new IncantoError("BAD_NODE_PATH", "Node path must not be empty.");
@@ -1274,6 +1613,16 @@ var SceneTree = class SceneTree {
1274
1613
  _detachRoot(node) {
1275
1614
  if (this._root === node) this._root = null;
1276
1615
  }
1616
+ /**
1617
+ * @internal Is this node already on its way out?
1618
+ *
1619
+ * A save taken from a `collected` handler runs BEFORE the deferred free, so
1620
+ * the pickup that triggered the checkpoint is still in the tree — and came
1621
+ * back on the next run while its score did not.
1622
+ */
1623
+ _isQueuedFree(node) {
1624
+ return this.freeQueue.has(node);
1625
+ }
1277
1626
  flushFreeQueue() {
1278
1627
  if (this.freeQueue.size === 0) return;
1279
1628
  const items = [...this.freeQueue];
@@ -1681,4 +2030,4 @@ function validateUniqueUids(root) {
1681
2030
  walk(root);
1682
2031
  }
1683
2032
  //#endregion
1684
- export { getBehavior as C, Signal as E, clearBehaviors as S, registeredBehaviors as T, InputMap as _, SCENE_FORMAT as a, behaviorSchema as b, SceneTree as c, resolveConstants as d, Node as f, resolveOrderGroups as g, effectiveOrder as h, serializeNode as i, CONST_REF_KEY as l, ORDER_GROUP_BASE as m, loadScene as n, computeViewport as o, parseNodePath as p, Scene as r, resolveViewport as s, buildNodeJson as t, isConstRef as u, diagnose as v, registerBehavior as w, behaviorSignals as x, Behavior as y };
2033
+ export { registerBehavior as A, InputMap as C, behaviorSignals as D, behaviorSchema as E, Signal as M, clearBehaviors as O, resolveOrderGroups as S, Behavior as T, restoreBehaviors as _, SCENE_FORMAT as a, ORDER_GROUP_BASE as b, SceneTree as c, resolveConstants as d, Node as f, captureBehaviors as g, behaviorsWithoutSave as h, serializeNode as i, registeredBehaviors as j, getBehavior as k, CONST_REF_KEY as l, SaveSlots as m, loadScene as n, computeViewport as o, parseNodePath as p, Scene as r, resolveViewport as s, buildNodeJson as t, isConstRef as u, savesWithoutUid as v, diagnose as w, effectiveOrder as x, createSaveStore as y };
@@ -1,4 +1,4 @@
1
- import { P as Scene, b as Engine } from "./behavior-62q0HWBO.js";
1
+ import { P as Scene, b as Engine } from "./behavior-rZNfzVbH.js";
2
2
  import { i as SceneJson } from "./schema-CFeioQRE.js";
3
3
 
4
4
  //#region src/core/scene/loader.d.ts
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-62q0HWBO.js";
1
+ import { Dt as Node, Nt as Signal, b as Engine, d as PropSchema } from "./behavior-rZNfzVbH.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
- import { n as loadScene } from "./loader-DwazzlQb.js";
2
- import { h as Engine } from "./register-uvaZj1KX.js";
1
+ import { n as loadScene } from "./loader-B2asghWa.js";
2
+ import { h as Engine } from "./register-CGq-Hee8.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-CB11yp21.js";
6
+ import { i as applySyncPatch, n as NetworkSpawner, r as NetworkManager, t as registerNodesNet } from "./register-CLVhzWcI.js";
7
7
  //#region src/net/loopback.ts
8
8
  /**
9
9
  * In-memory multiplayer hub implementing the SAME kernel contract as
@@ -1,4 +1,4 @@
1
- import { Et as Node, d as PropSchema, st as Listener } from "./behavior-62q0HWBO.js";
1
+ import { Dt as Node, ct as Listener, d as PropSchema } from "./behavior-rZNfzVbH.js";
2
2
 
3
3
  //#region src/core/nodes/audio-player.d.ts
4
4
  /**
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { v as diagnose } from "./loader-DwazzlQb.js";
2
+ import { w as diagnose } from "./loader-B2asghWa.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-BNPZYJmd.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-B_BaaGx-.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({
@@ -39,6 +39,7 @@ var Physics2D = class {
39
39
  world;
40
40
  events;
41
41
  kcc;
42
+ disconnectScene;
42
43
  disconnect;
43
44
  lastDt = 1 / 60;
44
45
  optsGravity;
@@ -63,6 +64,9 @@ var Physics2D = class {
63
64
  this.events = new R.EventQueue(true);
64
65
  this.unregisterDebug = registerDebugSource(this);
65
66
  this.disconnect = engine.fixedUpdated.connect((dt) => this.step(dt));
67
+ this.disconnectScene = engine.sceneChanged.connect(() => {
68
+ if (engine.scene) this.syncBodies();
69
+ });
66
70
  this.syncBodies();
67
71
  }
68
72
  /** @internal Driven by engine.fixedUpdated. */
@@ -90,7 +94,7 @@ var Physics2D = class {
90
94
  this.world.step(this.events);
91
95
  for (const [node, e] of this.entries) {
92
96
  const t = e.body.translation();
93
- if (!e.body.isFixed()) {
97
+ if (!e.body.isFixed() && !(node instanceof Area2D)) {
94
98
  const [ox, oy] = parentWorldOffset2D(node);
95
99
  node.position = [t.x * SCALE - ox, t.y * SCALE - oy];
96
100
  }
@@ -305,6 +309,7 @@ var Physics2D = class {
305
309
  }
306
310
  dispose() {
307
311
  this.disconnect();
312
+ this.disconnectScene();
308
313
  this.unregisterDebug();
309
314
  this.world.free();
310
315
  }
@@ -1,9 +1,9 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { v as diagnose } from "./loader-DwazzlQb.js";
2
+ import { w as diagnose } from "./loader-B2asghWa.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-02Btmmjn.js";
4
+ import { B as validateCollider3D, F as CharacterBody3D, I as PhysicsBody3D, L as RigidBody3D, P as Area3D, z as Node3D } from "./gameplay-bStgtZBV.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-CZOH5TY5.js";
6
+ import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-C08pOC6H.js";
7
7
  import { Euler, Matrix4, Quaternion, Vector3 } from "three";
8
8
  //#region src/3d/physics/collider-lines.ts
9
9
  /**
@@ -234,6 +234,7 @@ var Physics3D = class {
234
234
  world;
235
235
  events;
236
236
  kcc;
237
+ disconnectScene;
237
238
  disconnect;
238
239
  lastDt = 1 / 60;
239
240
  optsGravity;
@@ -259,6 +260,9 @@ var Physics3D = class {
259
260
  this.events = new R.EventQueue(true);
260
261
  this.unregisterDebug = registerDebugSource(this);
261
262
  this.disconnect = engine.fixedUpdated.connect((dt) => this.step(dt));
263
+ this.disconnectScene = engine.sceneChanged.connect(() => {
264
+ if (engine.scene) this.syncBodies();
265
+ });
262
266
  this.syncBodies();
263
267
  }
264
268
  /** Whether the solver runs at all. False = collider outlines only. */
@@ -291,7 +295,7 @@ var Physics3D = class {
291
295
  this.world.step(this.events);
292
296
  for (const [node, e] of this.entries) {
293
297
  const t = e.body.translation();
294
- if (!e.body.isFixed()) {
298
+ if (!e.body.isFixed() && !(node instanceof Area3D)) {
295
299
  const [ox, oy, oz] = parentWorldOffset3D(node);
296
300
  const next = [
297
301
  t.x - ox,
@@ -323,10 +327,10 @@ var Physics3D = class {
323
327
  e.lastV[1] = lv.y;
324
328
  e.lastV[2] = lv.z;
325
329
  }
326
- const wp = worldPosition3D(node);
327
- e.last[0] = wp[0];
328
- e.last[1] = wp[1];
329
- e.last[2] = wp[2];
330
+ const t2 = e.body.translation();
331
+ e.last[0] = t2.x;
332
+ e.last[1] = t2.y;
333
+ e.last[2] = t2.z;
330
334
  }
331
335
  this.events.drainCollisionEvents((h1, h2, started) => {
332
336
  const a = this.byColliderHandle.get(h1);
@@ -460,6 +464,7 @@ var Physics3D = class {
460
464
  }
461
465
  dispose() {
462
466
  this.disconnect();
467
+ this.disconnectScene();
463
468
  this.unregisterDebug();
464
469
  this.world.free();
465
470
  }
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-62q0HWBO.js";
1
+ import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-rZNfzVbH.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-DFBjMetZ.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-BgV6UbVA.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-BNaOC3Px.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-CkzKZ4v5.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;
@@ -1,5 +1,5 @@
1
- import { f as Node, h as effectiveOrder } from "./loader-DwazzlQb.js";
2
- import { t as registerCoreNodes } from "./register-uvaZj1KX.js";
1
+ import { f as Node, x as effectiveOrder } from "./loader-B2asghWa.js";
2
+ import { t as registerCoreNodes } from "./register-CGq-Hee8.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";