incanto 0.68.0 → 0.69.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 (75) hide show
  1. package/assets/catalog.json +9 -5
  2. package/bin/incanto-assets.mjs +14 -1
  3. package/bin/incanto-check.mjs +53 -3
  4. package/bin/incanto-new.mjs +29 -1
  5. package/bin/incanto-serve.mjs +160 -0
  6. package/bin/incanto-verify.mjs +40 -0
  7. package/bin/incanto.mjs +1 -0
  8. package/dist/2d.d.ts +7 -5
  9. package/dist/2d.js +4 -4
  10. package/dist/3d.d.ts +4 -4
  11. package/dist/3d.js +7 -7
  12. package/dist/{audio-player-DOrq7sP-.d.ts → audio-player-C0j2k-yB.d.ts} +32 -13
  13. package/dist/{behavior-DoFPYrgo.d.ts → behavior-rm8vVzu_.d.ts} +67 -0
  14. package/dist/{create-game-DbWtVTxD.js → create-game-CvJ1wSRP.js} +13 -9
  15. package/dist/{create-game-IZIydDwI.js → create-game-CwxEDlCm.js} +13 -9
  16. package/dist/debug.d.ts +1 -1
  17. package/dist/{duplicate-IWIqk0HJ.js → duplicate-Dj4L-5AA.js} +1 -1
  18. package/dist/editor.js +1 -1
  19. package/dist/{environment-presets-CybQXNqS.js → environment-presets-BO-7XoFV.js} +4 -4
  20. package/dist/{frame-report-DCnHFmto.d.ts → frame-report-DNxDAb1w.d.ts} +8 -0
  21. package/dist/{frame-report-BSMny7oe.js → frame-report-Dlq13Gyj.js} +1 -0
  22. package/dist/{gameplay-DM1eu_cV.js → gameplay-D1KixWK8.js} +157 -151
  23. package/dist/gameplay.d.ts +1 -1
  24. package/dist/gameplay.js +1 -1
  25. package/dist/index.d.ts +4 -4
  26. package/dist/index.js +6 -6
  27. package/dist/{loader-BC4PNtJX.js → loader-DZE7B07H.js} +22 -6
  28. package/dist/{loader-CcB533FR.d.ts → loader-DadV2QCT.d.ts} +1 -1
  29. package/dist/net.d.ts +2 -2
  30. package/dist/net.js +1 -1
  31. package/dist/{physics-2d-B7Y6dPZO.js → physics-2d-CF5yyjbj.js} +2 -2
  32. package/dist/{physics-3d-bG3n70Ky.js → physics-3d-DbYaEcZy.js} +3 -3
  33. package/dist/react.d.ts +1 -1
  34. package/dist/react.js +1 -1
  35. package/dist/{register-ibCjm-wH.js → register-DbVArsns.js} +19 -10
  36. package/dist/{register-3ta-2Xig.js → register-mmfugpaQ.js} +107 -15
  37. package/dist/{replay-CYvhVHHN.js → replay-BEHLDcQV.js} +2 -2
  38. package/dist/{replay-Dvn8aeBd.d.ts → replay-BQfkX4x7.d.ts} +1 -1
  39. package/dist/{sheet-grid-BT6N_Bjs.js → sheet-grid-Cea343VO.js} +6 -2
  40. package/dist/{split-screen-CYwDkbLF.js → split-screen-CauMwu6y.js} +2 -2
  41. package/dist/{split-screen-DhrSzZIB.d.ts → split-screen-Cg76MCV5.d.ts} +2 -2
  42. package/dist/{src-D7RIqXYF.js → src-CYEu-_S9.js} +1 -1
  43. package/dist/{teardown-D2NEmxPB.js → teardown-CMqFVxO9.js} +5 -4
  44. package/dist/{test-8hoHeRmo.js → test-D6ISmuFE.js} +60 -17
  45. package/dist/test.d.ts +15 -4
  46. package/dist/test.js +2 -2
  47. package/dist/vite.d.ts +70 -2
  48. package/dist/vite.js +176 -14
  49. package/dist/{webgl-unavailable-N9nQqesw.js → webgl-unavailable-Z5_g8x9H.js} +12 -1
  50. package/editor/assets/{agent8-BrrHOjMJ.js → agent8-BDvaZMQJ.js} +1 -1
  51. package/editor/assets/{debug-BBhKuBNV.js → debug-CMULinBW.js} +1 -1
  52. package/editor/assets/{index-eVd0BToA.js → index-CZIRr5EL.js} +91 -91
  53. package/editor/index.html +1 -1
  54. package/package.json +4 -3
  55. package/skills/incanto-assets.md +16 -2
  56. package/skills/incanto-audio.md +19 -3
  57. package/skills/incanto-building-2d-games.md +29 -0
  58. package/skills/incanto-building-3d-games.md +60 -2
  59. package/skills/incanto-gameplay-behaviors.md +18 -1
  60. package/skills/incanto-save-slots.md +27 -0
  61. package/skills/incanto-verifying-your-game.md +96 -2
  62. package/skills/incanto-your-first-game.md +2 -1
  63. package/templates-app/beacon-isle-3d/package.json +1 -1
  64. package/templates-app/beacon-isle-3d/src/main.ts +13 -3
  65. package/templates-app/platformer-2d/index.html +0 -23
  66. package/templates-app/platformer-2d/package.json +1 -1
  67. package/templates-app/platformer-2d/src/behaviors.ts +26 -16
  68. package/templates-app/platformer-2d/src/game.scene.json +17 -27
  69. package/templates-app/platformer-2d/src/main.ts +24 -12
  70. package/templates-app/star-survivor/package.json +1 -1
  71. package/templates-app/star-survivor/src/main.ts +17 -6
  72. package/templates-app/tps-3d/package.json +1 -1
  73. package/templates-app/tps-3d/src/main.ts +26 -15
  74. package/templates-app/village-quest-3d/package.json +1 -1
  75. package/templates-app/village-quest-3d/src/main.ts +13 -3
@@ -353,6 +353,15 @@ interface AudioEvent {
353
353
  bus: BusName;
354
354
  /** `engine.time` when it fired, in seconds. */
355
355
  at: number;
356
+ /**
357
+ * It repeats until stopped, rather than ending on its own.
358
+ *
359
+ * A looping sound is recorded ONCE — re-recording every pass would evict the
360
+ * rest of the log within seconds for a 0.2 s preset — so without this a
361
+ * headless check could not tell "the alarm loops" from "the alarm fired once
362
+ * and stopped". Both read `countOf('alarm') === 1`.
363
+ */
364
+ loop?: boolean;
356
365
  }
357
366
  declare class AudioBuses {
358
367
  /** Fires whenever any value changes (drives live re-gain of playing sounds). */
@@ -886,6 +895,10 @@ declare class InputMap {
886
895
  private readonly injectedDown;
887
896
  private readonly injectedPressed;
888
897
  private readonly injectedReleased;
898
+ private readonly injectedPressedNext;
899
+ private readonly injectedReleasedNext;
900
+ /** True between the start of a frame's update pass and `endFrame()`. */
901
+ private inFrame;
889
902
  private readonly injectedVectors;
890
903
  /**
891
904
  * Press a button ACTION directly — no key codes involved. This is how
@@ -1037,6 +1050,9 @@ declare class InputMap {
1037
1050
  };
1038
1051
  /** Consume one-frame edges. The Engine calls this at the end of every tick. */
1039
1052
  endFrame(): void;
1053
+ /** @internal The engine marks the update phase, so an edge injected inside
1054
+ * it can be held for the next frame. */
1055
+ beginFrame(): void;
1040
1056
  /**
1041
1057
  * Drop all action declarations and injected action state (physical key
1042
1058
  * state is kept). The Engine calls this on setScene so keybinds never
@@ -1654,6 +1670,24 @@ interface EngineStats {
1654
1670
  fps: number;
1655
1671
  /** Mean frame delta in ms over the same window (headless runs: 0). */
1656
1672
  frameMs: number;
1673
+ /**
1674
+ * How long ago the newest frame arrived, in ms. `null` when none has.
1675
+ *
1676
+ * `fps` is a rate over a WINDOW, so it keeps answering after the frames stop
1677
+ * — a hidden tab, a descheduled loop, a page the browser froze. Measured on
1678
+ * an engine that ticked 40 times and then stopped being ticked:
1679
+ *
1680
+ * ```
1681
+ * while ticking : fps 59.9
1682
+ * after 0 more ticks : fps 59.9 <- the last sample is 668 ms old
1683
+ * ```
1684
+ *
1685
+ * Both numbers are true about the window they describe; nothing said WHEN
1686
+ * that window was, so "60 fps" read the same whether it was measured 8 ms ago
1687
+ * or four seconds ago. A reader that cares should compare this against a
1688
+ * frame budget before trusting `fps`.
1689
+ */
1690
+ lastFrameAgeMs: number | null;
1657
1691
  /** Current node count of the active scene tree (no scene: 0). */
1658
1692
  nodes: number;
1659
1693
  /** Whether the loop is scheduled (start() without stop()/dispose()). */
@@ -1750,6 +1784,39 @@ declare class Engine {
1750
1784
  * learns about Rapier or three. From a behavior, prefer `this.physics`.
1751
1785
  */
1752
1786
  physics: PhysicsQuery | null;
1787
+ /**
1788
+ * How to build a physics world for a scene that needs one.
1789
+ *
1790
+ * `createGame2D`/`createGame3D` install this; core never learns what Rapier
1791
+ * is. It exists because `physics: 'auto'` can only look at the scene the game
1792
+ * BOOTED with, and the most universal act of finishing a game is putting a
1793
+ * title screen in front of it:
1794
+ *
1795
+ * ```
1796
+ * after boot on the title : engine.physics = null
1797
+ * after goToScene into game: engine.physics = null
1798
+ * player y after 2 s : 0 -> 0
1799
+ * ```
1800
+ *
1801
+ * The game rendered perfectly and was inert — nothing fell, nothing collided,
1802
+ * nothing could be collected or hurt. One scene swap turned a working game
1803
+ * into a diorama, and nothing was logged.
1804
+ */
1805
+ physicsProvider: ((root: Node) => Promise<void>) | null;
1806
+ private ensuring;
1807
+ /**
1808
+ * Give the current scene a physics world if it needs one and has none.
1809
+ *
1810
+ * Idempotent and safe to call on every swap: the provider decides whether the
1811
+ * incoming tree actually wants physics, and an explicit `physics: false` at
1812
+ * boot installs no provider at all, so opting out stays opted out.
1813
+ *
1814
+ * Asynchronous because the Rapier WASM has to load. The first frames after a
1815
+ * swap therefore run unsimulated — which every AI behaviour already tolerates
1816
+ * (`moveBody` falls back to a direct write when `_physics` is null) and which
1817
+ * is a hitch, where the alternative was a game that never simulated at all.
1818
+ */
1819
+ ensurePhysics(): Promise<void>;
1753
1820
  /** Seeded randomness for game logic (deterministic when `seed` is set). */
1754
1821
  readonly rng: Rng;
1755
1822
  /** The engine log channel (debug overlay + headless harness tail this). */
@@ -1,15 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-BC4PNtJX.js";
3
- import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-3ta-2Xig.js";
2
+ import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-DZE7B07H.js";
3
+ import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-mmfugpaQ.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-DEAmqGdf.js";
6
- import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-N9nQqesw.js";
7
- import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-D2NEmxPB.js";
8
- import { o as frameStats } from "./frame-report-BSMny7oe.js";
9
- import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-DM1eu_cV.js";
6
+ import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-Z5_g8x9H.js";
7
+ import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-CMqFVxO9.js";
8
+ import { o as frameStats } from "./frame-report-Dlq13Gyj.js";
9
+ import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-D1KixWK8.js";
10
10
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
11
- import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-CybQXNqS.js";
12
- import { n as enablePhysics3D } from "./physics-3d-bG3n70Ky.js";
11
+ import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-BO-7XoFV.js";
12
+ import { n as enablePhysics3D } from "./physics-3d-DbYaEcZy.js";
13
13
  import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
14
14
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
15
15
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
@@ -2249,6 +2249,10 @@ async function createGame3D(opts) {
2249
2249
  await report(.06, "scene");
2250
2250
  let physics = null;
2251
2251
  if (opts.physics === true || (opts.physics ?? "auto") === "auto" && hasBody(scene.root)) physics = await enablePhysics3D(engine);
2252
+ if (opts.physics !== false) engine.physicsProvider = async (root) => {
2253
+ if (engine.physics || !hasBody(root)) return;
2254
+ physics = await enablePhysics3D(engine);
2255
+ };
2252
2256
  await report(.1, "physics");
2253
2257
  const cleanups = [];
2254
2258
  const keyboard = opts.keyboard ?? (typeof window !== "undefined" ? window : false);
@@ -2416,7 +2420,7 @@ async function createGame3D(opts) {
2416
2420
  await report(1, "ready");
2417
2421
  function disposeGame() {
2418
2422
  teardown([
2419
- physics ? ["physics", () => physics?.dispose()] : null,
2423
+ ["physics", () => physics?.dispose()],
2420
2424
  ["app cleanups", () => {
2421
2425
  for (const cleanup of cleanups) cleanup();
2422
2426
  }],
@@ -1,15 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-BC4PNtJX.js";
3
- import { _ as AudioPlayer, v as Engine } from "./register-3ta-2Xig.js";
2
+ import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-DZE7B07H.js";
3
+ import { _ as AudioPlayer, v as Engine } from "./register-mmfugpaQ.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-DEAmqGdf.js";
6
- import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-N9nQqesw.js";
7
- import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-D2NEmxPB.js";
8
- import { o as frameStats } from "./frame-report-BSMny7oe.js";
9
- import { n as registerGameplayBehaviors } from "./gameplay-DM1eu_cV.js";
10
- import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-ibCjm-wH.js";
6
+ import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-Z5_g8x9H.js";
7
+ import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-CMqFVxO9.js";
8
+ import { o as frameStats } from "./frame-report-Dlq13Gyj.js";
9
+ import { n as registerGameplayBehaviors } from "./gameplay-D1KixWK8.js";
10
+ import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-DbVArsns.js";
11
11
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
12
- import { n as enablePhysics2D } from "./physics-2d-B7Y6dPZO.js";
12
+ import { n as enablePhysics2D } from "./physics-2d-CF5yyjbj.js";
13
13
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
14
14
  //#region src/2d/assets.ts
15
15
  /**
@@ -768,6 +768,10 @@ async function createGame2D(opts) {
768
768
  engine.setScene(scene);
769
769
  let physics = null;
770
770
  if (opts.physics === true || (opts.physics ?? "auto") === "auto" && hasBody(scene.root)) physics = await enablePhysics2D(engine);
771
+ if (opts.physics !== false) engine.physicsProvider = async (root) => {
772
+ if (engine.physics || !hasBody(root)) return;
773
+ physics = await enablePhysics2D(engine);
774
+ };
771
775
  const cleanups = [];
772
776
  const keyboard = opts.keyboard ?? (typeof window !== "undefined" ? window : false);
773
777
  if (keyboard) engine.input.attachKeyboard(keyboard);
@@ -910,7 +914,7 @@ async function createGame2D(opts) {
910
914
  engine.start();
911
915
  function disposeGame() {
912
916
  teardown([
913
- physics ? ["physics", () => physics?.dispose()] : null,
917
+ ["physics", () => physics?.dispose()],
914
918
  ["app cleanups", () => {
915
919
  for (const cleanup of cleanups) cleanup();
916
920
  }],
package/dist/debug.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-DoFPYrgo.js";
1
+ import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-rm8vVzu_.js";
2
2
 
3
3
  //#region src/debug/panel.d.ts
4
4
  /** Minimal document surface the overlay needs (injectable for tests). */
@@ -1,4 +1,4 @@
1
- import { a as serializeNode, t as buildNodeJson } from "./loader-BC4PNtJX.js";
1
+ import { a as serializeNode, t as buildNodeJson } from "./loader-DZE7B07H.js";
2
2
  //#region src/core/scene/duplicate.ts
3
3
  function stripUids(json) {
4
4
  const { uid: _uid, ...rest } = json;
package/dist/editor.js CHANGED
@@ -1983,7 +1983,7 @@ function an(e) {
1983
1983
  }
1984
1984
  //#endregion
1985
1985
  //#region ../engine/assets/catalog.json
1986
- var on = /*#__PURE__*/ JSON.parse("[{\"name\":\"2dbasic\",\"file\":\"characters/2dbasic.png\",\"url\":\"incanto/assets/characters/2dbasic.png\",\"kind\":\"character\",\"bytes\":30499,\"description\":\"2dbasic sprite sheet image.anything,base character. (frame size 192x192)\",\"animation\":\"characters/2dbasic.json\",\"frameWidth\":111,\"frameHeight\":83},{\"name\":\"attacked\",\"file\":\"audio/attacked.mp3\",\"url\":\"incanto/assets/audio/attacked.mp3\",\"kind\":\"audio\",\"bytes\":8757,\"description\":\"Short hurt / took-damage SFX for the player or an enemy.\"},{\"name\":\"bark_birch_color\",\"file\":\"vegetation/bark/birch_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":194186,\"description\":\"Birch bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_normal\",\"file\":\"vegetation/bark/birch_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":378046,\"description\":\"Birch bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_roughness\",\"file\":\"vegetation/bark/birch_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":127387,\"description\":\"Birch bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_color\",\"file\":\"vegetation/bark/oak_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":297877,\"description\":\"Oak bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_normal\",\"file\":\"vegetation/bark/oak_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":67610,\"description\":\"Oak bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_roughness\",\"file\":\"vegetation/bark/oak_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":16648,\"description\":\"Oak bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_color\",\"file\":\"vegetation/bark/pine_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":196361,\"description\":\"Pine bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_normal\",\"file\":\"vegetation/bark/pine_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":58237,\"description\":\"Pine bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_roughness\",\"file\":\"vegetation/bark/pine_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":36136,\"description\":\"Pine bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"box\",\"file\":\"items/box.png\",\"url\":\"incanto/assets/items/box.png\",\"kind\":\"item\",\"bytes\":10861,\"description\":\"Item box sprite for Dungeons and Dungeoners. Container sprite that holds random items or rewards when opened by player.\"},{\"name\":\"buff_potion\",\"file\":\"items/buff_potion.png\",\"url\":\"incanto/assets/items/buff_potion.png\",\"kind\":\"item\",\"bytes\":3809,\"description\":\"Buff potion item sprite for Dungeons and Dungeoners. Consumable item that grants temporary stat boosts or positive effects to player character.\"},{\"name\":\"coin\",\"file\":\"items/coin.png\",\"url\":\"incanto/assets/items/coin.png\",\"kind\":\"item\",\"bytes\":1689,\"description\":\"Gold coin collectible sprite for Dungeons and Dungeoners. Currency item with metallic sheen, used as in-game money or collectible reward.\"},{\"name\":\"explosion\",\"file\":\"audio/explosion.mp3\",\"url\":\"incanto/assets/audio/explosion.mp3\",\"kind\":\"audio\",\"bytes\":40124,\"description\":\"Impactful explosion / large destructive hit SFX. Pair with the Particles2D \\\"explosion\\\" preset.\"},{\"name\":\"floor00\",\"file\":\"tiles/floor00.jpg\",\"url\":\"incanto/assets/tiles/floor00.jpg\",\"kind\":\"tile\",\"bytes\":28736,\"description\":\"Basic floor tile texture for Dungeons and Dungeoners project, suitable for dungeon ground surfaces.\"},{\"name\":\"gem\",\"file\":\"items/gem.png\",\"url\":\"incanto/assets/items/gem.png\",\"kind\":\"item\",\"bytes\":8762,\"description\":\"Gem collectible sprite for Dungeons and Dungeoners. Valuable gemstone item used as currency, crafting material, or quest objective.\"},{\"name\":\"ghost\",\"file\":\"characters/ghost.png\",\"url\":\"incanto/assets/characters/ghost.png\",\"kind\":\"character\",\"bytes\":22933,\"description\":\"Ghost character with translucent appearance sprite sheet image (frame size 112x128)\",\"animation\":\"characters/ghost.json\",\"frameWidth\":112,\"frameHeight\":128},{\"name\":\"goblin\",\"file\":\"characters/goblin.png\",\"url\":\"incanto/assets/characters/goblin.png\",\"kind\":\"character\",\"bytes\":57994,\"description\":\"Medieval goblin with torch sprite sheet image (frame size 192x192)\",\"animation\":\"characters/goblin.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"gold\",\"file\":\"items/gold.png\",\"url\":\"incanto/assets/items/gold.png\",\"kind\":\"item\",\"bytes\":22313,\"description\":\"Gold item sprite for Dungeons and Dungeoners. Gold pile or gold bar sprite representing valuable currency or treasure reward.\"},{\"name\":\"gold-loot\",\"file\":\"audio/gold_loot.mp3\",\"url\":\"incanto/assets/audio/gold_loot.mp3\",\"kind\":\"audio\",\"bytes\":7506,\"description\":\"Metallic coin / gold pickup jingle — collecting currency.\"},{\"name\":\"ground_dirt\",\"file\":\"vegetation/ground/dirt_color.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_color.jpg\",\"kind\":\"foliage\",\"bytes\":231383,\"description\":\"Dense dirt/gravel ground texture (1024px) from the ez-tree demo app (MIT) — the reference meadow ground. Terrain3D grassland themes tile it for slope + noise-patch dirt by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_dirt_normal\",\"file\":\"vegetation/ground/dirt_normal.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_normal.jpg\",\"kind\":\"foliage\",\"bytes\":123478,\"description\":\"Dirt ground normal map (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes apply it across the whole ground band (demo parity); also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_grass\",\"file\":\"vegetation/ground/grass.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/grass.jpg\",\"kind\":\"foliage\",\"bytes\":322486,\"description\":\"Mossy meadow grass ground texture (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes (meadow/forest generators) tile it as the grass splat layer by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"heal\",\"file\":\"audio/heal.mp3\",\"url\":\"incanto/assets/audio/heal.mp3\",\"kind\":\"audio\",\"bytes\":29764,\"description\":\"Soothing health-restore / heal spell SFX.\"},{\"name\":\"hit-metal-bang\",\"file\":\"audio/hit_metal_bang.mp3\",\"url\":\"incanto/assets/audio/hit_metal_bang.mp3\",\"kind\":\"audio\",\"bytes\":17972,\"description\":\"Metallic impact — hitting armor, metal, or a blocked attack.\"},{\"name\":\"hp_potion\",\"file\":\"items/hp_potion.png\",\"url\":\"incanto/assets/items/hp_potion.png\",\"kind\":\"item\",\"bytes\":3513,\"description\":\"Health potion item sprite for Dungeons and Dungeoners. Consumable healing item that restores player health points when used.\"},{\"name\":\"ice-spear\",\"file\":\"audio/ice_spear.mp3\",\"url\":\"incanto/assets/audio/ice_spear.mp3\",\"kind\":\"audio\",\"bytes\":21315,\"description\":\"Sharp piercing ice projectile fire SFX.\"},{\"name\":\"leaves_ash\",\"file\":\"vegetation/ash_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ash_color.png\",\"kind\":\"foliage\",\"bytes\":181423,\"description\":\"Ash leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf/dead ash variants by default; copy it next to your game and set leafTexture to serve offline.\"},{\"name\":\"leaves_aspen\",\"file\":\"vegetation/aspen_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/aspen_color.png\",\"kind\":\"foliage\",\"bytes\":142116,\"description\":\"Aspen leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for high-tier broadleaf aspen variants; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_oak\",\"file\":\"vegetation/oak_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/oak_color.png\",\"kind\":\"foliage\",\"bytes\":238115,\"description\":\"Oak leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf oak variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_pine\",\"file\":\"vegetation/pine_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/pine_color.png\",\"kind\":\"foliage\",\"bytes\":303684,\"description\":\"Pine needle-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for conifer variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"locked_item_box\",\"file\":\"items/locked_item_box.png\",\"url\":\"incanto/assets/items/locked_item_box.png\",\"kind\":\"item\",\"bytes\":11074,\"description\":\"Locked item box sprite for Dungeons and Dungeoners. Container sprite requiring key or lockpick to open, containing valuable rewards.\"},{\"name\":\"map\",\"file\":\"items/map.png\",\"url\":\"incanto/assets/items/map.png\",\"kind\":\"item\",\"bytes\":3754,\"description\":\"Map item sprite for Dungeons and Dungeoners. Navigation item revealing dungeon layout or providing exploration assistance.\"},{\"name\":\"medieval-knight\",\"file\":\"characters/medieval-knight.png\",\"url\":\"incanto/assets/characters/medieval-knight.png\",\"kind\":\"character\",\"bytes\":84367,\"description\":\"(frame size 192x192) Using a medieval-themed SD(Super Deformed) knight sprite sheet image, you can apply idle, move, and attack animations, among others.\",\"animation\":\"characters/medieval-knight.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"minecraft-tiles\",\"file\":\"tiles/minecraft-tiles.png\",\"url\":\"incanto/assets/tiles/minecraft-tiles.png\",\"kind\":\"tile\",\"bytes\":10511,\"description\":\"Minecraft-themed tiles sprite sheet image (frame size 16x16)\"},{\"name\":\"monster-died\",\"file\":\"audio/monster_died.mp3\",\"url\":\"incanto/assets/audio/monster_died.mp3\",\"kind\":\"audio\",\"bytes\":16836,\"description\":\"Enemy defeat / death SFX.\"},{\"name\":\"resurrection_potion\",\"file\":\"items/resurrection_potion.png\",\"url\":\"incanto/assets/items/resurrection_potion.png\",\"kind\":\"item\",\"bytes\":3471,\"description\":\"Resurrection potion item sprite for Dungeons and Dungeoners. Rare consumable that revives fallen party members or prevents death.\"},{\"name\":\"slash\",\"file\":\"audio/slash.mp3\",\"url\":\"incanto/assets/audio/slash.mp3\",\"kind\":\"audio\",\"bytes\":10425,\"description\":\"Quick sword swing / melee slash SFX.\"},{\"name\":\"smite\",\"file\":\"audio/smite.mp3\",\"url\":\"incanto/assets/audio/smite.mp3\",\"kind\":\"audio\",\"bytes\":12956,\"description\":\"Powerful holy downward-strike SFX.\"},{\"name\":\"spells-cast\",\"file\":\"audio/spells_cast.mp3\",\"url\":\"incanto/assets/audio/spells_cast.mp3\",\"kind\":\"audio\",\"bytes\":22151,\"description\":\"Generic magical spell-cast / chant SFX.\"},{\"name\":\"super_box\",\"file\":\"items/super_box.png\",\"url\":\"incanto/assets/items/super_box.png\",\"kind\":\"item\",\"bytes\":12184,\"description\":\"Super item box sprite for Dungeons and Dungeoners. Premium container sprite containing rare or powerful items and equipment.\"},{\"name\":\"swoosh\",\"file\":\"effects/swoosh.png\",\"url\":\"incanto/assets/effects/swoosh.png\",\"kind\":\"effect\",\"bytes\":2599,\"description\":\"Swoosh effect sprite for Dungeons and Dungeoners. Motion blur or attack trail effect used for melee attacks, sword slashes, or fast movement animations.\"},{\"name\":\"trap\",\"file\":\"items/trap.png\",\"url\":\"incanto/assets/items/trap.png\",\"kind\":\"item\",\"bytes\":3969,\"description\":\"Trap object sprite for Dungeons and Dungeoners. Hazard sprite that damages players when triggered in dungeon exploration.\"},{\"name\":\"ui-click\",\"file\":\"audio/ui_click.wav\",\"url\":\"incanto/assets/audio/ui_click.wav\",\"kind\":\"audio\",\"bytes\":17332,\"description\":\"Short tactile UI click for menus and buttons.\"},{\"name\":\"walk\",\"file\":\"audio/walk.mp3\",\"url\":\"incanto/assets/audio/walk.mp3\",\"kind\":\"audio\",\"bytes\":5642,\"description\":\"Single footstep SFX for character movement (loop or one-shot).\"},{\"name\":\"wall00\",\"file\":\"tiles/wall00.jpg\",\"url\":\"incanto/assets/tiles/wall00.jpg\",\"kind\":\"tile\",\"bytes\":44344,\"description\":\"Basic wall tile texture for Dungeons and Dungeoners project, suitable for dungeon vertical boundaries.\"}]");
1986
+ var on = /*#__PURE__*/ JSON.parse("[{\"name\":\"2dbasic\",\"file\":\"characters/2dbasic.png\",\"url\":\"incanto/assets/characters/2dbasic.png\",\"kind\":\"character\",\"bytes\":30499,\"description\":\"2dbasic sprite sheet image.anything,base character.\",\"animation\":\"characters/2dbasic.json\",\"frameWidth\":111,\"frameHeight\":83},{\"name\":\"attacked\",\"file\":\"audio/attacked.mp3\",\"url\":\"incanto/assets/audio/attacked.mp3\",\"kind\":\"audio\",\"bytes\":8757,\"description\":\"Short hurt / took-damage SFX for the player or an enemy.\"},{\"name\":\"bark_birch_color\",\"file\":\"vegetation/bark/birch_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":194186,\"description\":\"Birch bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_normal\",\"file\":\"vegetation/bark/birch_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":378046,\"description\":\"Birch bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_roughness\",\"file\":\"vegetation/bark/birch_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":127387,\"description\":\"Birch bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_color\",\"file\":\"vegetation/bark/oak_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":297877,\"description\":\"Oak bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_normal\",\"file\":\"vegetation/bark/oak_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":67610,\"description\":\"Oak bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_roughness\",\"file\":\"vegetation/bark/oak_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":16648,\"description\":\"Oak bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_color\",\"file\":\"vegetation/bark/pine_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":196361,\"description\":\"Pine bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_normal\",\"file\":\"vegetation/bark/pine_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":58237,\"description\":\"Pine bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_roughness\",\"file\":\"vegetation/bark/pine_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":36136,\"description\":\"Pine bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"box\",\"file\":\"items/box.png\",\"url\":\"incanto/assets/items/box.png\",\"kind\":\"item\",\"bytes\":10861,\"description\":\"Item box sprite for Dungeons and Dungeoners. Container sprite that holds random items or rewards when opened by player.\"},{\"name\":\"buff_potion\",\"file\":\"items/buff_potion.png\",\"url\":\"incanto/assets/items/buff_potion.png\",\"kind\":\"item\",\"bytes\":3809,\"description\":\"Buff potion item sprite for Dungeons and Dungeoners. Consumable item that grants temporary stat boosts or positive effects to player character.\"},{\"name\":\"coin\",\"file\":\"items/coin.png\",\"url\":\"incanto/assets/items/coin.png\",\"kind\":\"item\",\"bytes\":1689,\"description\":\"Gold coin collectible sprite for Dungeons and Dungeoners. Currency item with metallic sheen, used as in-game money or collectible reward.\"},{\"name\":\"explosion\",\"file\":\"audio/explosion.mp3\",\"url\":\"incanto/assets/audio/explosion.mp3\",\"kind\":\"audio\",\"bytes\":40124,\"description\":\"Impactful explosion / large destructive hit SFX. Pair with the Particles2D \\\"explosion\\\" preset.\"},{\"name\":\"floor00\",\"file\":\"tiles/floor00.jpg\",\"url\":\"incanto/assets/tiles/floor00.jpg\",\"kind\":\"tile\",\"bytes\":28736,\"description\":\"Basic floor tile texture for Dungeons and Dungeoners project, suitable for dungeon ground surfaces.\"},{\"name\":\"gem\",\"file\":\"items/gem.png\",\"url\":\"incanto/assets/items/gem.png\",\"kind\":\"item\",\"bytes\":8762,\"description\":\"Gem collectible sprite for Dungeons and Dungeoners. Valuable gemstone item used as currency, crafting material, or quest objective.\"},{\"name\":\"ghost\",\"file\":\"characters/ghost.png\",\"url\":\"incanto/assets/characters/ghost.png\",\"kind\":\"character\",\"bytes\":22933,\"description\":\"Ghost character with translucent appearance sprite sheet image\",\"animation\":\"characters/ghost.json\",\"frameWidth\":112,\"frameHeight\":128},{\"name\":\"goblin\",\"file\":\"characters/goblin.png\",\"url\":\"incanto/assets/characters/goblin.png\",\"kind\":\"character\",\"bytes\":57994,\"description\":\"Medieval goblin with torch sprite sheet image\",\"animation\":\"characters/goblin.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"gold\",\"file\":\"items/gold.png\",\"url\":\"incanto/assets/items/gold.png\",\"kind\":\"item\",\"bytes\":22313,\"description\":\"Gold item sprite for Dungeons and Dungeoners. Gold pile or gold bar sprite representing valuable currency or treasure reward.\"},{\"name\":\"gold-loot\",\"file\":\"audio/gold_loot.mp3\",\"url\":\"incanto/assets/audio/gold_loot.mp3\",\"kind\":\"audio\",\"bytes\":7506,\"description\":\"Metallic coin / gold pickup jingle — collecting currency.\"},{\"name\":\"ground_dirt\",\"file\":\"vegetation/ground/dirt_color.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_color.jpg\",\"kind\":\"foliage\",\"bytes\":231383,\"description\":\"Dense dirt/gravel ground texture (1024px) from the ez-tree demo app (MIT) — the reference meadow ground. Terrain3D grassland themes tile it for slope + noise-patch dirt by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_dirt_normal\",\"file\":\"vegetation/ground/dirt_normal.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_normal.jpg\",\"kind\":\"foliage\",\"bytes\":123478,\"description\":\"Dirt ground normal map (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes apply it across the whole ground band (demo parity); also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_grass\",\"file\":\"vegetation/ground/grass.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/grass.jpg\",\"kind\":\"foliage\",\"bytes\":322486,\"description\":\"Mossy meadow grass ground texture (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes (meadow/forest generators) tile it as the grass splat layer by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"heal\",\"file\":\"audio/heal.mp3\",\"url\":\"incanto/assets/audio/heal.mp3\",\"kind\":\"audio\",\"bytes\":29764,\"description\":\"Soothing health-restore / heal spell SFX.\"},{\"name\":\"hit-metal-bang\",\"file\":\"audio/hit_metal_bang.mp3\",\"url\":\"incanto/assets/audio/hit_metal_bang.mp3\",\"kind\":\"audio\",\"bytes\":17972,\"description\":\"Metallic impact — hitting armor, metal, or a blocked attack.\"},{\"name\":\"hp_potion\",\"file\":\"items/hp_potion.png\",\"url\":\"incanto/assets/items/hp_potion.png\",\"kind\":\"item\",\"bytes\":3513,\"description\":\"Health potion item sprite for Dungeons and Dungeoners. Consumable healing item that restores player health points when used.\"},{\"name\":\"ice-spear\",\"file\":\"audio/ice_spear.mp3\",\"url\":\"incanto/assets/audio/ice_spear.mp3\",\"kind\":\"audio\",\"bytes\":21315,\"description\":\"Sharp piercing ice projectile fire SFX.\"},{\"name\":\"leaves_ash\",\"file\":\"vegetation/ash_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ash_color.png\",\"kind\":\"foliage\",\"bytes\":181423,\"description\":\"Ash leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf/dead ash variants by default; copy it next to your game and set leafTexture to serve offline.\"},{\"name\":\"leaves_aspen\",\"file\":\"vegetation/aspen_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/aspen_color.png\",\"kind\":\"foliage\",\"bytes\":142116,\"description\":\"Aspen leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for high-tier broadleaf aspen variants; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_oak\",\"file\":\"vegetation/oak_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/oak_color.png\",\"kind\":\"foliage\",\"bytes\":238115,\"description\":\"Oak leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf oak variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_pine\",\"file\":\"vegetation/pine_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/pine_color.png\",\"kind\":\"foliage\",\"bytes\":303684,\"description\":\"Pine needle-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for conifer variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"locked_item_box\",\"file\":\"items/locked_item_box.png\",\"url\":\"incanto/assets/items/locked_item_box.png\",\"kind\":\"item\",\"bytes\":11074,\"description\":\"Locked item box sprite for Dungeons and Dungeoners. Container sprite requiring key or lockpick to open, containing valuable rewards.\"},{\"name\":\"map\",\"file\":\"items/map.png\",\"url\":\"incanto/assets/items/map.png\",\"kind\":\"item\",\"bytes\":3754,\"description\":\"Map item sprite for Dungeons and Dungeoners. Navigation item revealing dungeon layout or providing exploration assistance.\"},{\"name\":\"medieval-knight\",\"file\":\"characters/medieval-knight.png\",\"url\":\"incanto/assets/characters/medieval-knight.png\",\"kind\":\"character\",\"bytes\":84367,\"description\":\"Using a medieval-themed SD(Super Deformed) knight sprite sheet image, you can apply idle, move, and attack animations, among others.\",\"animation\":\"characters/medieval-knight.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"minecraft-tiles\",\"file\":\"tiles/minecraft-tiles.png\",\"url\":\"incanto/assets/tiles/minecraft-tiles.png\",\"kind\":\"tile\",\"bytes\":10511,\"description\":\"Minecraft-themed tiles sprite sheet image\",\"frameWidth\":16,\"frameHeight\":16,\"columns\":5,\"tiles\":25},{\"name\":\"monster-died\",\"file\":\"audio/monster_died.mp3\",\"url\":\"incanto/assets/audio/monster_died.mp3\",\"kind\":\"audio\",\"bytes\":16836,\"description\":\"Enemy defeat / death SFX.\"},{\"name\":\"resurrection_potion\",\"file\":\"items/resurrection_potion.png\",\"url\":\"incanto/assets/items/resurrection_potion.png\",\"kind\":\"item\",\"bytes\":3471,\"description\":\"Resurrection potion item sprite for Dungeons and Dungeoners. Rare consumable that revives fallen party members or prevents death.\"},{\"name\":\"slash\",\"file\":\"audio/slash.mp3\",\"url\":\"incanto/assets/audio/slash.mp3\",\"kind\":\"audio\",\"bytes\":10425,\"description\":\"Quick sword swing / melee slash SFX.\"},{\"name\":\"smite\",\"file\":\"audio/smite.mp3\",\"url\":\"incanto/assets/audio/smite.mp3\",\"kind\":\"audio\",\"bytes\":12956,\"description\":\"Powerful holy downward-strike SFX.\"},{\"name\":\"spells-cast\",\"file\":\"audio/spells_cast.mp3\",\"url\":\"incanto/assets/audio/spells_cast.mp3\",\"kind\":\"audio\",\"bytes\":22151,\"description\":\"Generic magical spell-cast / chant SFX.\"},{\"name\":\"super_box\",\"file\":\"items/super_box.png\",\"url\":\"incanto/assets/items/super_box.png\",\"kind\":\"item\",\"bytes\":12184,\"description\":\"Super item box sprite for Dungeons and Dungeoners. Premium container sprite containing rare or powerful items and equipment.\"},{\"name\":\"swoosh\",\"file\":\"effects/swoosh.png\",\"url\":\"incanto/assets/effects/swoosh.png\",\"kind\":\"effect\",\"bytes\":2599,\"description\":\"Swoosh effect sprite for Dungeons and Dungeoners. Motion blur or attack trail effect used for melee attacks, sword slashes, or fast movement animations.\"},{\"name\":\"trap\",\"file\":\"items/trap.png\",\"url\":\"incanto/assets/items/trap.png\",\"kind\":\"item\",\"bytes\":3969,\"description\":\"Trap object sprite for Dungeons and Dungeoners. Hazard sprite that damages players when triggered in dungeon exploration.\"},{\"name\":\"ui-click\",\"file\":\"audio/ui_click.wav\",\"url\":\"incanto/assets/audio/ui_click.wav\",\"kind\":\"audio\",\"bytes\":17332,\"description\":\"Short tactile UI click for menus and buttons.\"},{\"name\":\"walk\",\"file\":\"audio/walk.mp3\",\"url\":\"incanto/assets/audio/walk.mp3\",\"kind\":\"audio\",\"bytes\":5642,\"description\":\"Single footstep SFX for character movement (loop or one-shot).\"},{\"name\":\"wall00\",\"file\":\"tiles/wall00.jpg\",\"url\":\"incanto/assets/tiles/wall00.jpg\",\"kind\":\"tile\",\"bytes\":44344,\"description\":\"Basic wall tile texture for Dungeons and Dungeoners project, suitable for dungeon vertical boundaries.\"}]");
1987
1987
  //#endregion
1988
1988
  //#region src/connections.ts
1989
1989
  function sn(e) {
@@ -1,12 +1,12 @@
1
- import { k as diagnose } from "./loader-BC4PNtJX.js";
2
- import { L as translateOn, t as registerCoreNodes } from "./register-3ta-2Xig.js";
1
+ import { k as diagnose } from "./loader-DZE7B07H.js";
2
+ import { L as translateOn, t as registerCoreNodes } from "./register-mmfugpaQ.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-CF70EArN.js";
6
6
  import { t as createNoise2D } from "./noise-CGUMx44x.js";
7
7
  import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
8
- import { B as rejectScale, G as StaticBody3D, H as CharacterBody3D, I as worldPosition, K as Node3D, L as Water3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, X as colliderFootDrop, w as tolerateUnknownAction, z as WaterCutout3D } from "./gameplay-DM1eu_cV.js";
9
- import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
8
+ import { B as rejectScale, G as StaticBody3D, H as CharacterBody3D, I as worldPosition, K as Node3D, L as Water3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, X as colliderFootDrop, w as tolerateUnknownAction, z as WaterCutout3D } from "./gameplay-D1KixWK8.js";
9
+ import { t as checkSheetGrid } from "./sheet-grid-Cea343VO.js";
10
10
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
11
11
  import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
12
12
  import { clone } from "three/addons/utils/SkeletonUtils.js";
@@ -30,6 +30,14 @@ interface FrameStats {
30
30
  grid: GridCell[][];
31
31
  /** What the frame is OF, or null when it is all background. */
32
32
  subject: Subject | null;
33
+ /**
34
+ * The page was HIDDEN when these pixels were read, so they are whatever it
35
+ * last drew.
36
+ *
37
+ * Added by the page, not computed from pixels — a stale buffer looks exactly
38
+ * like a live one. Undefined for a capture that never came from a browser.
39
+ */
40
+ hidden?: boolean;
33
41
  }
34
42
  /**
35
43
  * The thing in the shot: everything that is not the background.
@@ -177,6 +177,7 @@ const pct = (v) => `${(v * 100).toFixed(1)}%`;
177
177
  /** The report a person or an agent reads. Verdict first, numbers after. */
178
178
  function frameText(stats) {
179
179
  const lines = [];
180
+ if (stats.hidden) lines.push("THE PAGE IS HIDDEN — a browser stops animating a window covered by another, so these pixels are whatever it last drew. Bring it to the front and capture again.");
180
181
  if (stats.black) lines.push("BLACK SCREEN — nothing was drawn (no light, no camera, or nothing in view)");
181
182
  else if (stats.uniform) lines.push("one flat colour — the camera may be inside geometry, or only the sky is drawn");
182
183
  else if (!stats.subject) lines.push("nothing but background — the camera is pointed away from everything in the scene");