incanto 0.74.0 → 0.76.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 (92) hide show
  1. package/bin/incanto-multiplay.mjs +52 -4
  2. package/dist/2d.d.ts +83 -7
  3. package/dist/2d.js +4 -3
  4. package/dist/3d.d.ts +861 -167
  5. package/dist/3d.js +6 -6
  6. package/dist/{agent8-CHTT4unP.js → agent8-B-bh3n0X.js} +1 -1
  7. package/dist/{audio-player-BOrk4eQx.d.ts → audio-player-BRo2uvG6.d.ts} +23 -2
  8. package/dist/{behavior-J1cmVah0.d.ts → behavior-B_245qRy.d.ts} +15 -1
  9. package/dist/{create-game-ssvGvP7W.js → create-game-BMIPKrQW.js} +84 -8
  10. package/dist/{create-game-BAiA-FjP.js → create-game-Dai5vfVu.js} +80 -11
  11. package/dist/debug.d.ts +1 -1
  12. package/dist/{editor-switch-CFU9mCec.d.ts → editor-switch-Bzt0GzVp.d.ts} +13 -3
  13. package/dist/editor.js +1600 -1529
  14. package/dist/env.d.ts +1 -1
  15. package/dist/{environment-presets-BkqlWewf.js → environment-presets-e_9YCnGu.js} +2361 -104
  16. package/dist/{gameplay-Bxe1sMVT.js → gameplay-Bfff_beb.js} +10919 -6798
  17. package/dist/gameplay.d.ts +573 -31
  18. package/dist/gameplay.js +3 -2
  19. package/dist/index.d.ts +150 -6
  20. package/dist/index.js +6 -6
  21. package/dist/{loader-BAeWMYfF.d.ts → loader-CbkVdXL8.d.ts} +2 -2
  22. package/dist/net.d.ts +2 -2
  23. package/dist/net.js +2 -2
  24. package/dist/{physics-2d-C-SfvjzH.js → physics-2d-Tuf5LAyq.js} +250 -31
  25. package/dist/{physics-3d-rOzeg890.js → physics-3d-C5MOujfQ.js} +673 -51
  26. package/dist/{picking-BMV34Pjl.js → picking-DIwE48sU.js} +10 -7
  27. package/dist/{save-slots-CEUGeLuB.js → pose-ByFB_J3O.js} +217 -11
  28. package/dist/react.d.ts +2 -2
  29. package/dist/react.js +1 -1
  30. package/dist/{register-DRQyZKGU.js → register-7E3P1gz6.js} +191 -430
  31. package/dist/{register-CjociOtt.js → register-B768Qedj.js} +596 -2
  32. package/dist/{replay-B6BbgGM_.js → replay-DrqQ6dZj.js} +133 -18
  33. package/dist/{replay-wZK5Ok5c.d.ts → replay-W5nCw_cU.d.ts} +21 -2
  34. package/dist/{rng-Bb-IutXB.d.ts → rng-BsXZg3D6.d.ts} +7 -0
  35. package/dist/{split-screen-BxZ5rBe7.js → split-screen-B-dIcQsQ.js} +10 -5
  36. package/dist/{split-screen-D6sx8z3Z.d.ts → split-screen-CiLJf2-C.d.ts} +3 -3
  37. package/dist/{sprite-animation-Bz3DHD_4.js → sprite-animation-SQa5gIu2.js} +8 -6
  38. package/dist/{src-CqtvYtSN.js → src-D823V07k.js} +1 -1
  39. package/dist/{test-CEl0y2Sw.js → test-CVbxnXlv.js} +487 -82
  40. package/dist/test.d.ts +90 -12
  41. package/dist/test.js +2 -2
  42. package/dist/vite.js +34 -5
  43. package/editor/assets/{agent8-BlzturGi.js → agent8-DA-I5qhv.js} +1 -1
  44. package/editor/assets/{debug-BMUi8usj.js → debug-99tEPoGm.js} +1 -1
  45. package/editor/assets/index-Db74LZY-.js +11579 -0
  46. package/editor/index.html +1 -1
  47. package/package.json +1 -1
  48. package/schemas/scene.schema.json +1639 -280
  49. package/skills/incanto-3d-character.md +383 -20
  50. package/skills/incanto-audio.md +24 -2
  51. package/skills/incanto-building-2d-games.md +21 -2
  52. package/skills/incanto-building-3d-games.md +38 -3
  53. package/skills/incanto-editor.md +29 -8
  54. package/skills/incanto-environment.md +257 -14
  55. package/skills/incanto-game-feel.md +60 -1
  56. package/skills/incanto-gameplay-behaviors.md +668 -20
  57. package/skills/incanto-hud.md +116 -0
  58. package/skills/incanto-multiplayer.md +141 -2
  59. package/skills/incanto-node-reference.md +398 -16
  60. package/skills/incanto-performance.md +32 -0
  61. package/skills/incanto-physics-and-input.md +241 -13
  62. package/skills/incanto-playtesting.md +2 -2
  63. package/skills/incanto-save-slots.md +61 -2
  64. package/skills/incanto-scene-json-authoring.md +13 -0
  65. package/skills/incanto-verifying-your-game.md +86 -3
  66. package/templates-app/beacon-isle-3d/PROJECT/Status.md +12 -0
  67. package/templates-app/beacon-isle-3d/package.json +1 -1
  68. package/templates-app/beacon-isle-3d/src/game.scene.json +157 -3
  69. package/templates-app/molehill-2d/PROJECT/Status.md +7 -0
  70. package/templates-app/molehill-2d/package.json +1 -1
  71. package/templates-app/molehill-2d/src/game.scene.json +129 -2
  72. package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
  73. package/templates-app/platformer-2d/docs/project-2d-rules.md +3 -2
  74. package/templates-app/platformer-2d/package.json +1 -1
  75. package/templates-app/platformer-2d/src/behaviors.ts +40 -26
  76. package/templates-app/platformer-2d/src/game.scene.json +144 -2
  77. package/templates-app/platformer-2d/verify.ts +18 -1
  78. package/templates-app/star-survivor/PROJECT/Status.md +7 -0
  79. package/templates-app/star-survivor/package.json +1 -1
  80. package/templates-app/star-survivor/src/behaviors.ts +9 -8
  81. package/templates-app/star-survivor/src/game.scene.json +142 -4
  82. package/templates-app/star-survivor/verify.ts +13 -0
  83. package/templates-app/tps-3d/PROJECT/Status.md +6 -0
  84. package/templates-app/tps-3d/package.json +1 -1
  85. package/templates-app/tps-3d/src/game.scene.json +71 -10
  86. package/templates-app/village-quest-3d/PROJECT/Status.md +7 -0
  87. package/templates-app/village-quest-3d/package.json +1 -1
  88. package/templates-app/village-quest-3d/src/behaviors.ts +8 -16
  89. package/templates-app/village-quest-3d/src/grove.scene.json +121 -5
  90. package/templates-app/village-quest-3d/src/village.scene.json +126 -2
  91. package/templates-app/village-quest-3d/verify.ts +52 -2
  92. package/editor/assets/index-CrUCQoaB.js +0 -11046
@@ -1,7 +1,7 @@
1
- import { _ as AudioPlayer } from "./register-CjociOtt.js";
1
+ import { i as worldPosition } from "./pose-ByFB_J3O.js";
2
+ import { y as AudioPlayer } from "./register-B768Qedj.js";
2
3
  import { i as logReport, o as parseDrive } from "./webgl-unavailable-C8aDbGmR.js";
3
4
  import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-D-_7YF2G.js";
4
- import { et as worldPosition } from "./gameplay-Bxe1sMVT.js";
5
5
  //#region src/core/audio-errors.ts
6
6
  /** Every AudioPlayer under `root` whose source could not be played. */
7
7
  function audioErrors(root) {
@@ -359,11 +359,14 @@ async function openBundledEditor(opts) {
359
359
  await opts.play(working, camera);
360
360
  }, "starting the game…");
361
361
  },
362
- ...opts.exit ? { onExit: () => crossFade(async () => {
363
- handle?.dispose();
364
- handle = null;
365
- await opts.exit?.();
366
- }, "back to the game…") } : {}
362
+ ...opts.exit ? { onExit: () => {
363
+ const working = handle?.working();
364
+ return crossFade(async () => {
365
+ handle?.dispose();
366
+ handle = null;
367
+ await opts.exit?.(working);
368
+ }, "back to the game…");
369
+ } } : {}
367
370
  });
368
371
  }
369
372
  /**
@@ -425,10 +425,12 @@ function nodeRefWarnings(scene, opts = {}) {
425
425
  if (!bag) continue;
426
426
  for (const key of propKeys) {
427
427
  const value = bag[key];
428
- if (typeof value !== "string" || value === "") continue;
429
- const result = resolveRefInJson(root, at, value);
430
- if (result.ok) continue;
431
- warnings.push(`${path}: ${prefix}${key} — ${describeRefProblem(result.problem, value)} ` + (opts.fragment ? "This path leaves the fragment — only the host scene that instances it can answer, so this is fine if it resolves there and a typo if it does not." : "The scene loads and the prop does nothing."));
428
+ const entries = Array.isArray(value) ? value.flatMap((v, i) => typeof v === "string" && v !== "" ? [[`${key}[${i}]`, v]] : []) : typeof value === "string" && value !== "" ? [[key, value]] : [];
429
+ for (const [where, ref] of entries) {
430
+ const result = resolveRefInJson(root, at, ref);
431
+ if (result.ok) continue;
432
+ warnings.push(`${path}: ${prefix}${where} — ${describeRefProblem(result.problem, ref)} ` + (opts.fragment ? "This path leaves the fragment — only the host scene that instances it can answer, so this is fine if it resolves there and a typo if it does not." : "The scene loads and the prop does nothing."));
433
+ }
432
434
  }
433
435
  }
434
436
  (node.children ?? []).forEach((child, i) => {
@@ -1231,6 +1233,16 @@ function hasDom() {
1231
1233
  return typeof document !== "undefined";
1232
1234
  }
1233
1235
  /**
1236
+ * Is this widget switched off?
1237
+ *
1238
+ * `disabled` belongs to the widgets that can be pressed (`UiButton` today), not
1239
+ * to the base, so this asks rather than declares — a widget that grows the prop
1240
+ * later is out of the ring the day it does.
1241
+ */
1242
+ function isDisabled(widget) {
1243
+ return widget.disabled === true;
1244
+ }
1245
+ /**
1234
1246
  * The overlay container. One per scene is plenty; widgets mount into its
1235
1247
  * anchor slots. `zIndex` lifts it above game canvases; the layer never eats
1236
1248
  * pointer events (widgets that need clicks opt in individually).
@@ -1245,11 +1257,26 @@ var HudLayer = class HudLayer extends Node {
1245
1257
  * layer, Enter / A activates. OFF by default — a game whose HUD has a
1246
1258
  * button must not lose its arrow keys the moment one exists.
1247
1259
  */
1248
- focusNavigation: { default: false }
1260
+ focusNavigation: { default: false },
1261
+ /**
1262
+ * Cinematic bars: the fraction of the layer's height each bar covers,
1263
+ * 0..0.5, drawn full-bleed at the top and bottom edges over every widget.
1264
+ * Two `UiPanel`s could not do this — they sit in anchor slots, inside the
1265
+ * layer's padding, above the dialogue box. Animate it from a behaviour.
1266
+ */
1267
+ letterbox: {
1268
+ default: 0,
1269
+ range: {
1270
+ min: 0,
1271
+ max: .5
1272
+ }
1273
+ }
1249
1274
  };
1250
1275
  zIndex = 100;
1251
1276
  visible = true;
1252
1277
  focusNavigation = false;
1278
+ letterbox = 0;
1279
+ bars = null;
1253
1280
  /** @internal root overlay element (null headless). */
1254
1281
  _element = null;
1255
1282
  slots = /* @__PURE__ */ new Map();
@@ -1285,10 +1312,28 @@ var HudLayer = class HudLayer extends Node {
1285
1312
  this._element = null;
1286
1313
  this.slots.clear();
1287
1314
  }
1315
+ /** The two bars, made on first use and sized every frame from `letterbox`. */
1316
+ _syncLetterbox() {
1317
+ const el = this._element;
1318
+ if (!el) return;
1319
+ if (!this.bars) {
1320
+ const make = (edge) => {
1321
+ const bar = document.createElement("div");
1322
+ bar.dataset.incantoLetterbox = edge;
1323
+ bar.style.cssText = `position:absolute;left:0px;right:0px;${edge}:0px;height:0%;background:#000;pointer-events:none;z-index:1000;`;
1324
+ el.appendChild(bar);
1325
+ return bar;
1326
+ };
1327
+ this.bars = [make("top"), make("bottom")];
1328
+ }
1329
+ const pct = `${Math.round(Math.min(.5, Math.max(0, this.letterbox)) * 1e4) / 100}%`;
1330
+ for (const bar of this.bars) if (bar.style.height !== pct) bar.style.height = pct;
1331
+ }
1288
1332
  update() {
1289
1333
  if (this._element) {
1290
1334
  this._mount();
1291
1335
  this._element.style.display = this.visible ? "" : "none";
1336
+ this._syncLetterbox();
1292
1337
  }
1293
1338
  if (this.focusNavigation && this.ownsFocus()) this.stepFocus();
1294
1339
  }
@@ -1382,7 +1427,7 @@ var HudLayer = class HudLayer extends Node {
1382
1427
  if (!this.visible) return out;
1383
1428
  const walk = (node) => {
1384
1429
  if (node instanceof HudWidgetBase && !node.visible) return;
1385
- if (node instanceof HudWidgetBase && node.focusable) out.push(node);
1430
+ if (node instanceof HudWidgetBase && node.focusable && !isDisabled(node)) out.push(node);
1386
1431
  for (const child of node.children) walk(child);
1387
1432
  };
1388
1433
  walk(this);
@@ -2683,7 +2728,8 @@ var InputMap = class {
2683
2728
  const now = this.pointerPosition();
2684
2729
  const movedX = was && now ? now.x - was.x : 0;
2685
2730
  const movedY = was && now ? now.y - was.y : 0;
2686
- this.handlePointerMove(e.movementX ?? movedX, e.movementY ?? movedY);
2731
+ const native = document.pointerLockElement === target || e.pointerType === void 0 || e.pointerType === "mouse";
2732
+ this.handlePointerMove(native ? e.movementX ?? movedX : movedX, native ? e.movementY ?? movedY : movedY);
2687
2733
  }
2688
2734
  };
2689
2735
  const onCancel = (e) => {
@@ -5041,8 +5087,9 @@ function wireConnections(root, connections, declareSignals = false) {
5041
5087
  }
5042
5088
  fn.apply(self, args);
5043
5089
  };
5044
- const listener = (...args) => {
5045
- if (conn.filter && !matchesFilter(args[0], conn.filter)) return;
5090
+ const listener = (...emitted) => {
5091
+ if (conn.filter && !matchesFilter(emitted[0], conn.filter)) return;
5092
+ const args = conn.args ? [...conn.args] : emitted;
5046
5093
  if (conn.once) fromNode.off(conn.signal, listener);
5047
5094
  try {
5048
5095
  const fn = toNode[conn.handler];
@@ -5128,7 +5175,8 @@ const CONNECTION_KEYS = [
5128
5175
  "to",
5129
5176
  "handler",
5130
5177
  "once",
5131
- "filter"
5178
+ "filter",
5179
+ "args"
5132
5180
  ];
5133
5181
  /** …and every key its `filter` may carry. */
5134
5182
  const FILTER_KEYS = ["group", "tag"];
@@ -5156,6 +5204,7 @@ function validateConnectionShape(conn) {
5156
5204
  });
5157
5205
  }
5158
5206
  if (raw.once !== void 0 && typeof raw.once !== "boolean") throw new IncantoError("BAD_FORMAT", `Connection ${where}: "once" is true or false, not ${JSON.stringify(raw.once)} — every non-empty string is truthy, so it would fire exactly once.`, { prop: "once" });
5207
+ if (raw.args !== void 0 && !Array.isArray(raw.args)) throw new IncantoError("BAD_FORMAT", `Connection ${where}: "args" is a LIST of the arguments to call the handler with, not ${JSON.stringify(raw.args)} — write ["ENRAGED"] rather than "ENRAGED".`, { prop: "args" });
5159
5208
  if (raw.filter === void 0) return;
5160
5209
  if (typeof raw.filter !== "object" || raw.filter === null || Array.isArray(raw.filter)) throw new IncantoError("BAD_FORMAT", `Connection ${where}: "filter" is {group?, tag?}, not ${JSON.stringify(raw.filter)} — a filter the matcher cannot read passes EVERYTHING.`, { prop: "filter" });
5161
5210
  const filter = raw.filter;
@@ -5755,4 +5804,161 @@ function savesWithoutUid(root) {
5755
5804
  return out;
5756
5805
  }
5757
5806
  //#endregion
5758
- export { parseNodePath as $, SceneTree as A, HudLayer as B, sunDirectionFromSky as C, computeViewport as D, resolveConstants as E, resolveOrderGroups as F, UiText as G, TAPPABLE as H, InputMap as I, Node as J, requireNumber as K, handlerShadowWarnings as L, resetMemorySaves as M, ORDER_GROUP_BASE as N, resolveViewport as O, effectiveOrder as P, resolveRefInJson as Q, sceneDimension as R, sunDirectionFromElevationAzimuth as S, isConstRef as T, UiBanner as U, HudWidgetBase as V, UiBar as W, describeRefProblem as X, diagnose as Y, nodeRefWarnings as Z, Scene as _, restoreBehaviors as a, getBehavior as at, horizonColorFromSky as b, isCloned as c, Signal as ct, rebuildOptions as d, Behavior as et, rememberAuthoredPath as f, loader_exports as g, loadScene as h, captureBehaviors as i, clearBehaviors as it, createSaveStore as j, newUid as k, markCloned as l, buildSceneSubtree as m, SaveSlots as n, behaviorSchema as nt, savesWithoutUid as o, registerBehavior as ot, stripUids as p, requireText as q, behaviorsWithoutSave as r, behaviorSignals as rt, duplicateNode as s, registeredBehaviors as st, ENGINE_STATE_KEY as t, StubBehavior as tt, markTemplateName as u, serializeNode as v, CONST_REF_KEY as w, parseEnvironment3D as x, SCENE_FORMAT as y, FITS$1 as z };
5807
+ //#region src/core/pose.ts
5808
+ /** Duck-type test: every spatial node (Node2D/Node3D) exposes `position: number[]`. */
5809
+ function hasPosition(node) {
5810
+ return Array.isArray(node.position);
5811
+ }
5812
+ const DEG = Math.PI / 180;
5813
+ /** Rotation matrix (row-major 3×3) of an Euler XYZ triple in degrees — three's 'XYZ' order. */
5814
+ function mat3FromEuler(rot) {
5815
+ const a = (rot[0] ?? 0) * DEG;
5816
+ const b = (rot[1] ?? 0) * DEG;
5817
+ const c = (rot[2] ?? 0) * DEG;
5818
+ const ca = Math.cos(a);
5819
+ const sa = Math.sin(a);
5820
+ const cb = Math.cos(b);
5821
+ const sb = Math.sin(b);
5822
+ const cc = Math.cos(c);
5823
+ const sc = Math.sin(c);
5824
+ return [
5825
+ cb * cc,
5826
+ -cb * sc,
5827
+ sb,
5828
+ ca * sc + sa * sb * cc,
5829
+ ca * cc - sa * sb * sc,
5830
+ -sa * cb,
5831
+ sa * sc - ca * sb * cc,
5832
+ sa * cc + ca * sb * sc,
5833
+ ca * cb
5834
+ ];
5835
+ }
5836
+ function mat3Mul(a, b) {
5837
+ const o = new Array(9);
5838
+ for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) o[r * 3 + c] = a[r * 3] * b[c] + a[r * 3 + 1] * b[3 + c] + a[r * 3 + 2] * b[6 + c];
5839
+ return o;
5840
+ }
5841
+ function mat3Apply(m, v) {
5842
+ const x = v[0] ?? 0;
5843
+ const y = v[1] ?? 0;
5844
+ const z = v[2] ?? 0;
5845
+ return [
5846
+ m[0] * x + m[1] * y + m[2] * z,
5847
+ m[3] * x + m[4] * y + m[5] * z,
5848
+ m[6] * x + m[7] * y + m[8] * z
5849
+ ];
5850
+ }
5851
+ function mat3ApplyT(m, v) {
5852
+ const x = v[0] ?? 0;
5853
+ const y = v[1] ?? 0;
5854
+ const z = v[2] ?? 0;
5855
+ return [
5856
+ m[0] * x + m[3] * y + m[6] * z,
5857
+ m[1] * x + m[4] * y + m[7] * z,
5858
+ m[2] * x + m[5] * y + m[8] * z
5859
+ ];
5860
+ }
5861
+ const IDENTITY = [
5862
+ 1,
5863
+ 0,
5864
+ 0,
5865
+ 0,
5866
+ 1,
5867
+ 0,
5868
+ 0,
5869
+ 0,
5870
+ 1
5871
+ ];
5872
+ /**
5873
+ * The pose of `node`'s PARENT frame in world space, composed through every
5874
+ * spatial ancestor — position AND rotation. It used to sum positions only, so
5875
+ * a child two metres down +z of a hull turned 90° was reported at world +z,
5876
+ * where nothing was drawn: the renderer composes the parent's rotation, and
5877
+ * every reader of this helper (a turret's muzzle, a camera under a rig, a
5878
+ * guard's eyes) disagreed with the picture by exactly that turn.
5879
+ */
5880
+ function parentPose(node) {
5881
+ const chain = [];
5882
+ for (let at = node.parent; at; at = at.parent) if (hasPosition(at)) chain.push(at);
5883
+ const position = [
5884
+ 0,
5885
+ 0,
5886
+ 0
5887
+ ];
5888
+ let rot3 = IDENTITY;
5889
+ let angle2 = 0;
5890
+ for (let i = chain.length - 1; i >= 0; i--) {
5891
+ const n = chain[i];
5892
+ const local = n.position;
5893
+ if (local.length >= 3) {
5894
+ const moved = mat3Apply(rot3, local);
5895
+ position[0] = (position[0] ?? 0) + (moved[0] ?? 0);
5896
+ position[1] = (position[1] ?? 0) + (moved[1] ?? 0);
5897
+ position[2] = (position[2] ?? 0) + (moved[2] ?? 0);
5898
+ if (Array.isArray(n.rotation)) rot3 = mat3Mul(rot3, mat3FromEuler(n.rotation));
5899
+ } else {
5900
+ const a = angle2 * DEG;
5901
+ const x = local[0] ?? 0;
5902
+ const y = local[1] ?? 0;
5903
+ position[0] = (position[0] ?? 0) + x * Math.cos(a) - y * Math.sin(a);
5904
+ position[1] = (position[1] ?? 0) + x * Math.sin(a) + y * Math.cos(a);
5905
+ if (typeof n.rotation === "number") angle2 += n.rotation;
5906
+ }
5907
+ }
5908
+ return {
5909
+ position,
5910
+ rot3,
5911
+ angle2
5912
+ };
5913
+ }
5914
+ /** The node's position in WORLD space — its parents' positions and rotations composed. */
5915
+ function worldPosition(node) {
5916
+ const own = node.position;
5917
+ if (!Array.isArray(own)) return [];
5918
+ const p = parentPose(node);
5919
+ if (own.length >= 3) {
5920
+ const moved = mat3Apply(p.rot3, own);
5921
+ return [
5922
+ (p.position[0] ?? 0) + (moved[0] ?? 0),
5923
+ (p.position[1] ?? 0) + (moved[1] ?? 0),
5924
+ (p.position[2] ?? 0) + (moved[2] ?? 0)
5925
+ ];
5926
+ }
5927
+ const a = p.angle2 * DEG;
5928
+ const x = own[0] ?? 0;
5929
+ const y = own[1] ?? 0;
5930
+ return [(p.position[0] ?? 0) + x * Math.cos(a) - y * Math.sin(a), (p.position[1] ?? 0) + x * Math.sin(a) + y * Math.cos(a)];
5931
+ }
5932
+ /**
5933
+ * A LOCAL vector turned into world space by the node's own rotation and every
5934
+ * ancestor's — a barrel's forward, a muzzle's offset, a hardpoint's direction.
5935
+ *
5936
+ * `worldPosition` answers where a node IS; this answers which way it points,
5937
+ * and two games wrote it by hand (a tank's `forwardOf`, an artillery piece's
5938
+ * barrel tip) because nothing else could say it. `worldDirection(node, [0,0,1])`
5939
+ * is the +Z-forward convention every 3D skin in this engine follows.
5940
+ */
5941
+ function worldDirection(node, local) {
5942
+ const p = parentPose(node);
5943
+ const own = node.rotation;
5944
+ if (local.length >= 3 || Array.isArray(own)) return mat3Apply(Array.isArray(own) ? mat3Mul(p.rot3, mat3FromEuler(own)) : p.rot3, local);
5945
+ const a = (p.angle2 + (typeof own === "number" ? own : 0)) * DEG;
5946
+ const x = local[0] ?? 0;
5947
+ const y = local[1] ?? 0;
5948
+ return [x * Math.cos(a) - y * Math.sin(a), x * Math.sin(a) + y * Math.cos(a)];
5949
+ }
5950
+ /** The local `position` that puts `node` at `world` — the inverse of `worldPosition`. */
5951
+ function localFromWorld(node, world) {
5952
+ const p = parentPose(node);
5953
+ if (world.length >= 3) return mat3ApplyT(p.rot3, [
5954
+ (world[0] ?? 0) - (p.position[0] ?? 0),
5955
+ (world[1] ?? 0) - (p.position[1] ?? 0),
5956
+ (world[2] ?? 0) - (p.position[2] ?? 0)
5957
+ ]);
5958
+ const a = -p.angle2 * DEG;
5959
+ const x = (world[0] ?? 0) - (p.position[0] ?? 0);
5960
+ const y = (world[1] ?? 0) - (p.position[1] ?? 0);
5961
+ return [x * Math.cos(a) - y * Math.sin(a), x * Math.sin(a) + y * Math.cos(a)];
5962
+ }
5963
+ //#endregion
5964
+ export { Node as $, isConstRef as A, resolveOrderGroups as B, serializeNode as C, sunDirectionFromElevationAzimuth as D, parseEnvironment3D as E, SceneTree as F, HudLayer as G, handlerShadowWarnings as H, createSaveStore as I, UiBanner as J, HudWidgetBase as K, resetMemorySaves as L, computeViewport as M, resolveViewport as N, sunDirectionFromSky as O, newUid as P, requireText as Q, ORDER_GROUP_BASE as R, Scene as S, horizonColorFromSky as T, sceneDimension as U, InputMap as V, FITS$1 as W, UiText as X, UiBar as Y, requireNumber as Z, stripUids as _, ENGINE_STATE_KEY as a, Behavior as at, loadScene as b, captureBehaviors as c, behaviorSignals as ct, duplicateNode as d, registerBehavior as dt, diagnose as et, isCloned as f, registeredBehaviors as ft, rememberAuthoredPath as g, rebuildOptions as h, worldPosition as i, parseNodePath as it, resolveConstants as j, CONST_REF_KEY as k, restoreBehaviors as l, clearBehaviors as lt, markTemplateName as m, localFromWorld as n, nodeRefWarnings as nt, SaveSlots as o, StubBehavior as ot, markCloned as p, Signal as pt, TAPPABLE as q, worldDirection as r, resolveRefInJson as rt, behaviorsWithoutSave as s, behaviorSchema as st, hasPosition as t, describeRefProblem as tt, savesWithoutUid as u, getBehavior as ut, buildNodeJson as v, SCENE_FORMAT as w, loader_exports as x, buildSceneSubtree as y, effectiveOrder as z };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-J1cmVah0.js";
2
- import { c as JsonValue } from "./rng-Bb-IutXB.js";
1
+ import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-B_245qRy.js";
2
+ import { c as JsonValue } from "./rng-BsXZg3D6.js";
3
3
  import { CSSProperties, ReactNode } from "react";
4
4
 
5
5
  //#region src/react/index.d.ts
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-BAiA-FjP.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-ssvGvP7W.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-Dai5vfVu.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-BMIPKrQW.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;