incanto 0.6.0 → 0.7.1

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 (33) hide show
  1. package/dist/2d.d.ts +9 -2
  2. package/dist/2d.js +3 -3
  3. package/dist/3d.d.ts +11 -3
  4. package/dist/3d.js +3 -3
  5. package/dist/{audio-player-DkBqRTs4.d.ts → audio-player-C3bH_eZ5.d.ts} +1 -1
  6. package/dist/{behavior-CWhW3oa6.d.ts → behavior-q3cejJgs.d.ts} +192 -174
  7. package/dist/{create-game-B_sW_eiE.js → create-game-DuDkqnjl.js} +87 -4
  8. package/dist/{create-game-DkbZCNaV.js → create-game-rFulaS3s.js} +75 -4
  9. package/dist/debug.d.ts +3 -1
  10. package/dist/debug.js +59 -6
  11. package/dist/gameplay.d.ts +1 -1
  12. package/dist/index.d.ts +21 -4
  13. package/dist/index.js +3 -3
  14. package/dist/{loader-D2u0fVW2.d.ts → loader-DnLMMRy8.d.ts} +1 -1
  15. package/dist/net.d.ts +1 -1
  16. package/dist/{particle-sim-CFkILGwh.js → particle-sim-m3CdTGSl.js} +43 -2
  17. package/dist/{physics-2d-Cgli1aju.js → physics-2d-CZM5Y90X.js} +1 -1
  18. package/dist/{physics-3d-CBAQ12LY.js → physics-3d-DT5e8izo.js} +1 -1
  19. package/dist/react.d.ts +1 -1
  20. package/dist/react.js +1 -1
  21. package/dist/{register-BJCfuuZ2.js → register-Cl3pAxX-.js} +34 -5
  22. package/dist/{register-Dd7Juujf.js → register-CpXcMiEk.js} +44 -3
  23. package/dist/test.d.ts +2 -2
  24. package/dist/test.js +7 -7
  25. package/editor/assets/{agent8-MciFwn0v.js → agent8-N4bwVH7C.js} +1 -1
  26. package/editor/assets/{index-mofVSmuA.js → index-CXFNanuR.js} +81 -81
  27. package/editor/index.html +1 -1
  28. package/package.json +1 -1
  29. package/schemas/scene.schema.json +175 -0
  30. package/skills/incanto-behaviors-and-scripts.md +25 -0
  31. package/skills/incanto-node-reference.md +35 -0
  32. package/skills/incanto-scene-json-authoring.md +19 -0
  33. package/skills/incanto-verifying-your-game.md +9 -0
@@ -1,14 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { _ as registerBehavior, n as loadScene } from "./loader-B4OEXDZ8.js";
3
- import { a as Engine } from "./particle-sim-CFkILGwh.js";
3
+ import { s as Engine } from "./particle-sim-m3CdTGSl.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { s as AudioPlayer } from "./register-Dl_ixIJe.js";
6
6
  import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
7
7
  import { n as registerGameplayBehaviors } from "./gameplay-CDFgSG6z.js";
8
8
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
9
- import { O as PhysicsBody3D, c as ModelInstance3D, d as DirectionalLight3D, j as Node3D, t as registerNodes3D, y as Camera3D } from "./register-Dd7Juujf.js";
10
- import { n as enablePhysics3D } from "./physics-3d-CBAQ12LY.js";
11
- import { ACESFilmicToneMapping, AmbientLight, 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";
9
+ import { O as PhysicsBody3D, c as ModelInstance3D, d as DirectionalLight3D, j as Node3D, t as registerNodes3D, y as Camera3D } from "./register-CpXcMiEk.js";
10
+ import { n as enablePhysics3D } from "./physics-3d-DT5e8izo.js";
11
+ 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";
12
12
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
13
13
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
14
14
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
@@ -1073,6 +1073,54 @@ function parseIblIntensity(value) {
1073
1073
  return value;
1074
1074
  }
1075
1075
  //#endregion
1076
+ //#region src/3d/selection-outline.ts
1077
+ /**
1078
+ * Where IS the node the dev-overlay selected? — world-space outline segments
1079
+ * for the renderer's highlight pass. A renderable node gets its actual
1080
+ * bounding box (children included); a node with no visual extent gets a
1081
+ * small marker cube at its world position so it is still findable.
1082
+ */
1083
+ const box = new Box3();
1084
+ const size = new Vector3();
1085
+ const MARKER_HALF = .4;
1086
+ /** 12 box edges = 24 points × xyz. */
1087
+ const OUT = new Float32Array(72);
1088
+ function selectionOutline3D(node) {
1089
+ if (!(node instanceof Node3D)) return null;
1090
+ const obj = node._ensureObject3D();
1091
+ obj.updateWorldMatrix(true, true);
1092
+ box.setFromObject(obj);
1093
+ box.getSize(size);
1094
+ if (!Number.isFinite(size.x) || size.x === 0 && size.y === 0 && size.z === 0) {
1095
+ const p = new Vector3().setFromMatrixPosition(obj.matrixWorld);
1096
+ box.min.set(p.x - MARKER_HALF, p.y - MARKER_HALF, p.z - MARKER_HALF);
1097
+ box.max.set(p.x + MARKER_HALF, p.y + MARKER_HALF, p.z + MARKER_HALF);
1098
+ } else box.expandByScalar(.02);
1099
+ const { min, max } = box;
1100
+ let i = 0;
1101
+ const seg = (x1, y1, z1, x2, y2, z2) => {
1102
+ OUT[i++] = x1;
1103
+ OUT[i++] = y1;
1104
+ OUT[i++] = z1;
1105
+ OUT[i++] = x2;
1106
+ OUT[i++] = y2;
1107
+ OUT[i++] = z2;
1108
+ };
1109
+ seg(min.x, min.y, min.z, max.x, min.y, min.z);
1110
+ seg(max.x, min.y, min.z, max.x, min.y, max.z);
1111
+ seg(max.x, min.y, max.z, min.x, min.y, max.z);
1112
+ seg(min.x, min.y, max.z, min.x, min.y, min.z);
1113
+ seg(min.x, max.y, min.z, max.x, max.y, min.z);
1114
+ seg(max.x, max.y, min.z, max.x, max.y, max.z);
1115
+ seg(max.x, max.y, max.z, min.x, max.y, max.z);
1116
+ seg(min.x, max.y, max.z, min.x, max.y, min.z);
1117
+ seg(min.x, min.y, min.z, min.x, max.y, min.z);
1118
+ seg(max.x, min.y, min.z, max.x, max.y, min.z);
1119
+ seg(max.x, min.y, max.z, max.x, max.y, max.z);
1120
+ seg(min.x, min.y, max.z, min.x, max.y, max.z);
1121
+ return OUT;
1122
+ }
1123
+ //#endregion
1076
1124
  //#region src/3d/sync.ts
1077
1125
  function isSpatialConsumer(node) {
1078
1126
  return node.spatial === true && typeof node._setSpatialPose === "function";
@@ -1449,9 +1497,31 @@ var Renderer3D = class {
1449
1497
  this.debugLines.renderOrder = 9999;
1450
1498
  this.debugLines.visible = false;
1451
1499
  this.threeScene.add(this.debugLines);
1500
+ this.selectionLines = new LineSegments(new BufferGeometry(), new LineBasicMaterial({
1501
+ color: "#ffb020",
1502
+ transparent: true,
1503
+ depthTest: false
1504
+ }));
1505
+ this.selectionLines.frustumCulled = false;
1506
+ this.selectionLines.renderOrder = 1e4;
1507
+ this.selectionLines.visible = false;
1508
+ this.threeScene.add(this.selectionLines);
1452
1509
  this.disconnect = this.engine.updated.connect(() => this.render());
1453
1510
  }
1454
1511
  debugLines;
1512
+ selectionLines;
1513
+ syncSelectionOutline() {
1514
+ const node = this.engine.debugSelection;
1515
+ if (node && node.tree !== this.engine.scene?.tree) this.engine.debugSelection = null;
1516
+ const current = this.engine.debugSelection;
1517
+ const vertices = current ? selectionOutline3D(current) : null;
1518
+ this.selectionLines.visible = vertices !== null;
1519
+ if (vertices) {
1520
+ this.selectionLines.geometry.setAttribute("position", new BufferAttribute(vertices, 3));
1521
+ const attr = this.selectionLines.geometry.getAttribute("position");
1522
+ attr.needsUpdate = true;
1523
+ }
1524
+ }
1455
1525
  syncDebugLines() {
1456
1526
  let vertices = null;
1457
1527
  for (const source of debugSources("3d")) {
@@ -1465,6 +1535,7 @@ var Renderer3D = class {
1465
1535
  const scene = this.engine.scene;
1466
1536
  if (!scene) return;
1467
1537
  this.syncDebugLines();
1538
+ this.syncSelectionOutline();
1468
1539
  if (scene.assets && !this.loadedAssetScenes.has(scene)) {
1469
1540
  this.assets.load(scene.assets);
1470
1541
  this.loadedAssetScenes.add(scene);
package/dist/debug.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as RendererStats, k as LogLevel, v as Engine } from "./behavior-CWhW3oa6.js";
1
+ import { C as RendererStats, E as LogLevel, v as Engine } from "./behavior-q3cejJgs.js";
2
2
 
3
3
  //#region src/debug/panel.d.ts
4
4
  /** Minimal document surface the overlay needs (injectable for tests). */
@@ -32,6 +32,8 @@ declare class DebugOverlay {
32
32
  private readonly menuButton;
33
33
  private dropdown;
34
34
  private selected;
35
+ /** Explorer subtrees the user collapsed (nodes keep identity across frames). */
36
+ private readonly collapsedFlags;
35
37
  private statsChip;
36
38
  private readonly logRows;
37
39
  private readonly levelEnabled;
package/dist/debug.js CHANGED
@@ -178,6 +178,8 @@ var DebugOverlay = class {
178
178
  menuButton;
179
179
  dropdown = null;
180
180
  selected = null;
181
+ /** Explorer subtrees the user collapsed (nodes keep identity across frames). */
182
+ collapsedFlags = /* @__PURE__ */ new Map();
181
183
  statsChip = null;
182
184
  logRows = [];
183
185
  levelEnabled = {
@@ -326,6 +328,7 @@ var DebugOverlay = class {
326
328
  }
327
329
  }
328
330
  dispose() {
331
+ this.engine.debugSelection = null;
329
332
  this.setConsoleCapture(false);
330
333
  for (const cleanup of this.cleanups) cleanup();
331
334
  for (const id of [...this.panels.keys()]) this.close(id);
@@ -418,26 +421,75 @@ var DebugOverlay = class {
418
421
  clear(panel.body);
419
422
  const root = this.engine.scene?.root;
420
423
  if (!root) return;
421
- const renderNode = (node, depth) => {
424
+ const renderNode = (node, container) => {
422
425
  const ctor = node.constructor;
426
+ const hasKids = node.children.length > 0;
427
+ const isCollapsed = this.collapsedFlags.get(node) === true;
423
428
  const row = this.doc.createElement("div");
424
- row.textContent = `${" ".repeat(depth)}${node.name} (${ctor.typeName})`;
425
429
  applyStyle(row, {
426
- whiteSpace: "pre",
430
+ display: "flex",
431
+ alignItems: "center",
427
432
  cursor: "pointer",
428
433
  padding: "1px 2px",
434
+ borderRadius: "3px",
429
435
  background: node === this.selected ? "rgba(110,160,255,0.25)" : "transparent"
430
436
  });
437
+ const chevron = this.doc.createElement("span");
438
+ chevron.textContent = hasKids ? isCollapsed ? "▸" : "▾" : "·";
439
+ applyStyle(chevron, {
440
+ width: "14px",
441
+ flex: "none",
442
+ textAlign: "center",
443
+ opacity: hasKids ? "0.85" : "0.25",
444
+ userSelect: "none"
445
+ });
446
+ if (hasKids) chevron.addEventListener("click", (e) => {
447
+ e.stopPropagation?.();
448
+ this.collapsedFlags.set(node, !isCollapsed);
449
+ this.renderExplorer();
450
+ });
451
+ row.appendChild(chevron);
452
+ const label = this.doc.createElement("span");
453
+ label.textContent = node.name;
454
+ applyStyle(label, { whiteSpace: "nowrap" });
455
+ row.appendChild(label);
456
+ const type = this.doc.createElement("span");
457
+ type.textContent = ` ${ctor.typeName}`;
458
+ applyStyle(type, {
459
+ opacity: "0.45",
460
+ whiteSpace: "nowrap",
461
+ fontSize: "10px"
462
+ });
463
+ row.appendChild(type);
464
+ if (hasKids && isCollapsed) {
465
+ const count = this.doc.createElement("span");
466
+ count.textContent = ` (${node.children.length})`;
467
+ applyStyle(count, {
468
+ opacity: "0.35",
469
+ fontSize: "10px"
470
+ });
471
+ row.appendChild(count);
472
+ }
431
473
  row.addEventListener("click", () => {
432
474
  this.selected = node;
475
+ this.engine.debugSelection = node;
433
476
  this.open("inspector");
434
477
  this.renderExplorer();
435
478
  this.renderInspector();
436
479
  });
437
- panel.body.appendChild(row);
438
- for (const child of node.children) renderNode(child, depth + 1);
480
+ container.appendChild(row);
481
+ if (hasKids && !isCollapsed) {
482
+ const kids = this.doc.createElement("div");
483
+ applyStyle(kids, {
484
+ marginLeft: "8px",
485
+ paddingLeft: "8px",
486
+ borderLeft: "1px solid rgba(255,255,255,0.14)"
487
+ });
488
+ for (const child of node.children) renderNode(child, kids);
489
+ container.appendChild(kids);
490
+ }
439
491
  };
440
- renderNode(root, 0);
492
+ renderNode(root, panel.body);
441
493
  }
442
494
  renderInspector() {
443
495
  const panel = this.panels.get("inspector");
@@ -446,6 +498,7 @@ var DebugOverlay = class {
446
498
  let node = this.selected;
447
499
  if (node && node.tree === null) {
448
500
  this.selected = null;
501
+ this.engine.debugSelection = null;
449
502
  node = null;
450
503
  }
451
504
  if (!node) {
@@ -1,5 +1,5 @@
1
1
  import { c as JsonValue } from "./schema-CcoWb32N.js";
2
- import { T as Node, l as PropSchema, n as BehaviorCtor, t as Behavior, v as Engine } from "./behavior-CWhW3oa6.js";
2
+ import { Z as Node, l as PropSchema, n as BehaviorCtor, t as Behavior, v as Engine } from "./behavior-q3cejJgs.js";
3
3
 
4
4
  //#region src/gameplay/chase.d.ts
5
5
  /**
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  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-CcoWb32N.js";
2
- import { $ as BusName, A as LogManager, B as spatialGain, C as RendererStats, D as SceneTree, E as NodeLifecycle, F as Listener, G as SfxWave, H as SFX_PRESETS, I as ROLLOFF_MODELS, J as MusicBackend, K as SynthOptions, L as RolloffModel, M as SfxEngine, N as SfxPlayOptions, O as LogEntry, P as isAudioContextAvailable, Q as AudioBuses, R as SpatialParams, S as GameStats, T as Node, U as SFX_PRESET_NAMES, V as spatialPan, W as SfxParams, X as MusicTrack, Y as MusicManager, Z as PlayMusicOptions, _ as registeredTypes, a as registerBehavior, b as Scheduler, c as PropDef, d as createNode, et as Signal, f as getNodeSchema, g as registerNode, h as mergeStaticSignals, i as getBehavior, j as InputMap, k as LogLevel, l as PropSchema, m as getNodeType, n as BehaviorCtor, o as registeredBehaviors, p as getNodeSignals, q as synthSfx, r as clearBehaviors, s as NodeCtor, t as Behavior, tt as SignalListener, u as clearRegistry, v as Engine, w as Scene, x as EngineStats, y as EngineOptions, z as Vec3 } from "./behavior-CWhW3oa6.js";
3
- import { n as loadScene, t as LoadSceneOptions } from "./loader-D2u0fVW2.js";
2
+ import { $ as Signal, A as SfxPlayOptions, B as SFX_PRESET_NAMES, C as RendererStats, D as LogManager, E as LogLevel, F as SpatialParams, G as MusicBackend, H as SfxWave, I as Vec3, J as PlayMusicOptions, K as MusicManager, L as spatialGain, M as Listener, N as ROLLOFF_MODELS, O as InputMap, P as RolloffModel, Q as NodeLifecycle, R as spatialPan, S as GameStats, T as LogEntry, U as SynthOptions, V as SfxParams, W as synthSfx, X as BusName, Y as AudioBuses, Z as Node, _ as registeredTypes, a as registerBehavior, b as Scheduler, c as PropDef, d as createNode, et as SignalListener, f as getNodeSchema, g as registerNode, h as mergeStaticSignals, i as getBehavior, j as isAudioContextAvailable, k as SfxEngine, l as PropSchema, m as getNodeType, n as BehaviorCtor, o as registeredBehaviors, p as getNodeSignals, q as MusicTrack, r as clearBehaviors, s as NodeCtor, t as Behavior, tt as SceneTree, u as clearRegistry, v as Engine, w as Scene, x as EngineStats, y as EngineOptions, z as SFX_PRESETS } from "./behavior-q3cejJgs.js";
3
+ import { n as loadScene, t as LoadSceneOptions } from "./loader-DnLMMRy8.js";
4
4
  import { n as ParticleSimConfig, r as ParticleView, t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
5
- import { n as AudioPlayer, t as AudioElementLike } from "./audio-player-DkBqRTs4.js";
5
+ import { n as AudioPlayer, t as AudioElementLike } from "./audio-player-C3bH_eZ5.js";
6
6
  import { n as IncantoErrorCode, r as IncantoErrorDetails, t as IncantoError } from "./errors-BMFaY68Q.js";
7
7
 
8
8
  //#region src/core/audio/crossfade.d.ts
@@ -218,6 +218,23 @@ declare class Timer extends Node {
218
218
  */
219
219
  declare function createNoise2D(seed: number): (x: number, y: number) => number;
220
220
  //#endregion
221
+ //#region src/core/order-groups.d.ts
222
+ /**
223
+ * Named draw-order bands — Unity's "sorting layers" for both dimensions.
224
+ * A node's effective render order is `base(orderGroup) + renderOrder`, so
225
+ * `renderOrder` stays a FINE offset within its band and whole categories
226
+ * layer correctly without magic numbers:
227
+ *
228
+ * background < terrain < default < characters < effects < overlay
229
+ *
230
+ * Engine type defaults: particles sit in `effects`, Terrain3D in `terrain`;
231
+ * everything else is `default` (base 0 — identical to pre-band behavior).
232
+ */
233
+ type OrderGroup = "background" | "terrain" | "default" | "characters" | "effects" | "overlay";
234
+ declare const ORDER_GROUP_BASE: Record<OrderGroup, number>;
235
+ /** base + fine offset (unknown group names fall back to `default`). */
236
+ declare function effectiveOrder(group: string, renderOrder: number): number;
237
+ //#endregion
221
238
  //#region src/core/particle-presets.d.ts
222
239
  /**
223
240
  * Predefined particle looks. A node's `preset` seeds these values UNDER its
@@ -436,4 +453,4 @@ declare function computeViewport(canvasW: number, canvasH: number, viewport: {
436
453
  /** Engine version. Kept in sync with package.json by the release pipeline. */
437
454
  declare const VERSION: string;
438
455
  //#endregion
439
- export { AudioBuses, type AudioElementLike, AudioPlayer, Behavior, type BehaviorCtor, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, Engine, type EngineOptions, type EngineStats, type GameStats, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LoadSceneOptions, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, ROLLOFF_MODELS, type RendererStats, type ResolvedRendering, type ResolvedViewport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiText, VERSION, type Vec3, type ViewportFit, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, fadeGain, getBehavior, getNodeSchema, getNodeSignals, getNodeType, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, synthSfx };
456
+ export { AudioBuses, type AudioElementLike, AudioPlayer, Behavior, type BehaviorCtor, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, Engine, type EngineOptions, type EngineStats, type GameStats, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LoadSceneOptions, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, ROLLOFF_MODELS, type RendererStats, type ResolvedRendering, type ResolvedViewport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiText, VERSION, type Vec3, type ViewportFit, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, getBehavior, getNodeSchema, getNodeSignals, getNodeType, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, synthSfx };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as registerBehavior, a as SCENE_FORMAT, c as SceneTree, d as resolveConstants, f as Node, g as getBehavior, h as clearBehaviors, i as serializeNode, l as CONST_REF_KEY, m as Behavior, n as loadScene, o as computeViewport, p as parseNodePath, r as Scene, s as resolveViewport, u as isConstRef, v as registeredBehaviors, y as Signal } from "./loader-B4OEXDZ8.js";
2
- import { a as Engine, c as SfxEngine, d as WebAudioMusicBackend, f as crossfadeGains, i as applyParticlePreset, l as isAudioContextAvailable, m as AudioBuses, n as PARTICLE_PRESETS, o as LogManager, p as fadeGain, r as PARTICLE_PRESET_NAMES, s as InputMap, t as ParticleSim, u as MusicManager } from "./particle-sim-CFkILGwh.js";
2
+ import { a as ORDER_GROUP_BASE, c as LogManager, d as isAudioContextAvailable, f as MusicManager, g as AudioBuses, h as fadeGain, i as applyParticlePreset, l as InputMap, m as crossfadeGains, n as PARTICLE_PRESETS, o as effectiveOrder, p as WebAudioMusicBackend, r as PARTICLE_PRESET_NAMES, s as Engine, t as ParticleSim, u as SfxEngine } from "./particle-sim-m3CdTGSl.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 { a as UiBar, c as ROLLOFF_MODELS, d as SFX_PRESETS, f as SFX_PRESET_NAMES, i as UiBanner, l as spatialGain, n as Timer, o as UiText, p as synthSfx, r as HudLayer, s as AudioPlayer, t as registerCoreNodes, u as spatialPan } from "./register-Dl_ixIJe.js";
@@ -110,6 +110,6 @@ function newUid() {
110
110
  //#endregion
111
111
  //#region src/index.ts
112
112
  /** Engine version. Kept in sync with package.json by the release pipeline. */
113
- const VERSION = "0.6.0";
113
+ const VERSION = "0.7.1";
114
114
  //#endregion
115
- export { AudioBuses, AudioPlayer, Behavior, CONST_REF_KEY, Engine, HudLayer, IncantoError, InputMap, LogManager, MusicManager, Node, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, Scene, SceneTree, SfxEngine, Signal, Timer, TouchControls, UiBanner, UiBar, UiText, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, fadeGain, getBehavior, getNodeSchema, getNodeSignals, getNodeType, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, synthSfx };
115
+ export { AudioBuses, AudioPlayer, Behavior, CONST_REF_KEY, Engine, HudLayer, IncantoError, InputMap, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, Scene, SceneTree, SfxEngine, Signal, Timer, TouchControls, UiBanner, UiBar, UiText, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, getBehavior, getNodeSchema, getNodeSignals, getNodeType, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, resolveConstants, resolveRendering, resolveViewport, serializeNode, spatialGain, spatialPan, synthSfx };
@@ -1,5 +1,5 @@
1
1
  import { i as SceneJson } from "./schema-CcoWb32N.js";
2
- import { v as Engine, w as Scene } from "./behavior-CWhW3oa6.js";
2
+ import { v as Engine, w as Scene } from "./behavior-q3cejJgs.js";
3
3
 
4
4
  //#region src/core/scene/loader.d.ts
5
5
  interface LoadSceneOptions {
package/dist/net.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CcoWb32N.js";
2
- import { T as Node, et as Signal, l as PropSchema, v as Engine } from "./behavior-CWhW3oa6.js";
2
+ import { $ as Signal, Z as Node, l as PropSchema, v as Engine } from "./behavior-q3cejJgs.js";
3
3
 
4
4
  //#region src/net/types.d.ts
5
5
  type Unsubscribe = () => void;
@@ -1011,6 +1011,28 @@ var Engine = class {
1011
1011
  * timers, behaviors all breathe together. See `gameplay` `hitStop()`.
1012
1012
  */
1013
1013
  timeScale = 1;
1014
+ /**
1015
+ * The node the dev overlay has selected (renderers draw its bounding box
1016
+ * as an orange outline in the game view so you can SEE what you picked).
1017
+ * Null when nothing is selected; cleared automatically when it leaves the
1018
+ * tree. Set by the debug overlay — games normally never touch this.
1019
+ */
1020
+ debugSelection = null;
1021
+ _time = 0;
1022
+ _unscaledTime = 0;
1023
+ /**
1024
+ * Elapsed GAME time in seconds since the scene started — the sum of every
1025
+ * scaled dt (freezes at timeScale 0, crawls in slow motion). Unity's
1026
+ * `Time.time`. Resets on `setScene`.
1027
+ */
1028
+ get time() {
1029
+ return this._time;
1030
+ }
1031
+ /** Elapsed REAL time in seconds since the scene started (ignores timeScale) —
1032
+ * UI animations that must keep moving during slow-mo/pause read this. */
1033
+ get unscaledTime() {
1034
+ return this._unscaledTime;
1035
+ }
1014
1036
  constructor(opts = {}) {
1015
1037
  this.fixedStep = 1 / (opts.fixedHz ?? 60);
1016
1038
  this.maxFixedSteps = opts.maxFixedStepsPerTick ?? 5;
@@ -1028,6 +1050,8 @@ var Engine = class {
1028
1050
  this._scene = scene;
1029
1051
  scene.tree._setEngine(this);
1030
1052
  this.input.clear();
1053
+ this._time = 0;
1054
+ this._unscaledTime = 0;
1031
1055
  if (scene.input) this.input.declare(scene.input);
1032
1056
  this.sceneChanged.emit(scene);
1033
1057
  }
@@ -1107,7 +1131,10 @@ var Engine = class {
1107
1131
  this.lastMs = nowMs;
1108
1132
  return;
1109
1133
  }
1110
- const dt = Math.min((nowMs - this.lastMs) / 1e3, MAX_DT_SECONDS) * this.timeScale;
1134
+ const rawDt = Math.min((nowMs - this.lastMs) / 1e3, MAX_DT_SECONDS);
1135
+ const dt = rawDt * this.timeScale;
1136
+ this._time += dt;
1137
+ this._unscaledTime += rawDt;
1111
1138
  this.lastMs = nowMs;
1112
1139
  const scene = this._scene;
1113
1140
  if (!scene) return;
@@ -1132,6 +1159,20 @@ function countNodes(root) {
1132
1159
  return n;
1133
1160
  }
1134
1161
  //#endregion
1162
+ //#region src/core/order-groups.ts
1163
+ const ORDER_GROUP_BASE = {
1164
+ background: -2e3,
1165
+ terrain: -1e3,
1166
+ default: 0,
1167
+ characters: 1e3,
1168
+ effects: 2e3,
1169
+ overlay: 3e3
1170
+ };
1171
+ /** base + fine offset (unknown group names fall back to `default`). */
1172
+ function effectiveOrder(group, renderOrder) {
1173
+ return (ORDER_GROUP_BASE[group] ?? 0) + renderOrder;
1174
+ }
1175
+ //#endregion
1135
1176
  //#region src/core/particle-presets.ts
1136
1177
  const PARTICLE_PRESETS = {
1137
1178
  fire: {
@@ -1397,4 +1438,4 @@ var ParticleSim = class {
1397
1438
  }
1398
1439
  };
1399
1440
  //#endregion
1400
- export { Engine as a, SfxEngine as c, WebAudioMusicBackend as d, crossfadeGains as f, applyParticlePreset as i, isAudioContextAvailable as l, AudioBuses as m, PARTICLE_PRESETS as n, LogManager as o, fadeGain as p, PARTICLE_PRESET_NAMES as r, InputMap as s, ParticleSim as t, MusicManager as u };
1441
+ export { ORDER_GROUP_BASE as a, LogManager as c, isAudioContextAvailable as d, MusicManager as f, AudioBuses as g, fadeGain as h, applyParticlePreset as i, InputMap as l, crossfadeGains as m, PARTICLE_PRESETS as n, effectiveOrder as o, WebAudioMusicBackend as p, PARTICLE_PRESET_NAMES as r, Engine as s, ParticleSim as t, SfxEngine as u };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
3
- import { _ as validateCollider2D, d as Area2D, f as CharacterBody2D, g as Node2D, m as RigidBody2D, p as PhysicsBody2D, u as Joint2D } from "./register-BJCfuuZ2.js";
3
+ import { _ as validateCollider2D, d as Area2D, f as CharacterBody2D, g as Node2D, m as RigidBody2D, p as PhysicsBody2D, u as Joint2D } from "./register-Cl3pAxX-.js";
4
4
  import { n as registerDebugSource } from "./debug-draw-CZmOYjL2.js";
5
5
  //#region src/2d/physics/physics-2d.ts
6
6
  var physics_2d_exports = /* @__PURE__ */ __exportAll({
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
3
3
  import { n as registerDebugSource } from "./debug-draw-CZmOYjL2.js";
4
- import { D as CharacterBody3D, E as Area3D, M as validateCollider3D, O as PhysicsBody3D, T as Joint3D, j as Node3D, k as RigidBody3D, x as Terrain3D } from "./register-Dd7Juujf.js";
4
+ import { D as CharacterBody3D, E as Area3D, M as validateCollider3D, O as PhysicsBody3D, T as Joint3D, j as Node3D, k as RigidBody3D, x as Terrain3D } from "./register-CpXcMiEk.js";
5
5
  import { Euler, Quaternion } from "three";
6
6
  //#region src/3d/physics/physics-3d.ts
7
7
  var physics_3d_exports = /* @__PURE__ */ __exportAll({
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { c as JsonValue } from "./schema-CcoWb32N.js";
2
- import { n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-CWhW3oa6.js";
2
+ import { n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-q3cejJgs.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-DkbZCNaV.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-B_sW_eiE.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-rFulaS3s.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DuDkqnjl.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;
@@ -1,5 +1,5 @@
1
1
  import { f as Node } from "./loader-B4OEXDZ8.js";
2
- import { i as applyParticlePreset, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-CFkILGwh.js";
2
+ import { i as applyParticlePreset, o as effectiveOrder, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-m3CdTGSl.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 { t as registerCoreNodes } from "./register-Dl_ixIJe.js";
@@ -45,6 +45,17 @@ var Node2D = class extends Node {
45
45
  static: { default: false },
46
46
  scale: { default: [1, 1] },
47
47
  renderOrder: { default: 0 },
48
+ orderGroup: {
49
+ default: "default",
50
+ options: [
51
+ "background",
52
+ "terrain",
53
+ "default",
54
+ "characters",
55
+ "effects",
56
+ "overlay"
57
+ ]
58
+ },
48
59
  visible: { default: true }
49
60
  };
50
61
  /** Legacy alias: old 2D scenes (and `zIndex`-trained agents) keep loading —
@@ -60,6 +71,12 @@ var Node2D = class extends Node {
60
71
  scale = [1, 1];
61
72
  /** Draw order among 2D drawables (higher = on top); matches 3D `renderOrder`. */
62
73
  renderOrder = 0;
74
+ /** Named draw-order band; `renderOrder` is the fine offset inside it. */
75
+ orderGroup = "default";
76
+ /** What three actually sorts by: band base + renderOrder. */
77
+ get effectiveRenderOrder() {
78
+ return effectiveOrder(this.orderGroup, this.renderOrder);
79
+ }
63
80
  visible = true;
64
81
  _object2D = null;
65
82
  /** @internal The backing three object (lazily created). */
@@ -308,7 +325,7 @@ var Sprite2D = class extends Node2D {
308
325
  const ax = this.anchor[0] ?? .5;
309
326
  const ay = this.anchor[1] ?? .5;
310
327
  quad.position.set((.5 - ax) * w, (ay - .5) * h, 0);
311
- quad.renderOrder = this.renderOrder;
328
+ quad.renderOrder = this.effectiveRenderOrder;
312
329
  mat.color.set(this.tint);
313
330
  mat.opacity = this.opacity;
314
331
  }
@@ -571,7 +588,7 @@ var ColorRect2D = class extends Node2D {
571
588
  const ax = this.anchor[0] ?? .5;
572
589
  const ay = this.anchor[1] ?? .5;
573
590
  quad.position.set((.5 - ax) * w, (ay - .5) * h, 0);
574
- quad.renderOrder = this.renderOrder;
591
+ quad.renderOrder = this.effectiveRenderOrder;
575
592
  const mat = quad.material;
576
593
  mat.color.set(this.color);
577
594
  mat.opacity = this.opacity;
@@ -627,7 +644,7 @@ var Label = class extends Node2D {
627
644
  this.rasterize();
628
645
  }
629
646
  quad.visible = true;
630
- quad.renderOrder = this.renderOrder;
647
+ quad.renderOrder = this.effectiveRenderOrder;
631
648
  }
632
649
  rasterize() {
633
650
  const dpr = Math.min(globalThis.devicePixelRatio ?? 1, 2);
@@ -669,9 +686,21 @@ const UNIT_PLANE = new PlaneGeometry(1, 1);
669
686
  * Simulation is deterministic under the engine seed.
670
687
  */
671
688
  var Particles2D = class Particles2D extends Node2D {
689
+ orderGroup = "effects";
672
690
  static typeName = "Particles2D";
673
691
  static signals = ["finished"];
674
692
  static props = {
693
+ orderGroup: {
694
+ default: "effects",
695
+ options: [
696
+ "background",
697
+ "terrain",
698
+ "default",
699
+ "characters",
700
+ "effects",
701
+ "overlay"
702
+ ]
703
+ },
675
704
  preset: {
676
705
  default: "custom",
677
706
  options: ["custom", ...PARTICLE_PRESET_NAMES]
@@ -837,7 +866,7 @@ var Particles2D = class Particles2D extends Node2D {
837
866
  mesh.count = index;
838
867
  mesh.instanceMatrix.needsUpdate = true;
839
868
  if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;
840
- mesh.renderOrder = this.renderOrder;
869
+ mesh.renderOrder = this.effectiveRenderOrder;
841
870
  }
842
871
  };
843
872
  const matrixScratch = new Matrix4();
@@ -1,5 +1,5 @@
1
1
  import { f as Node } from "./loader-B4OEXDZ8.js";
2
- import { i as applyParticlePreset, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-CFkILGwh.js";
2
+ import { i as applyParticlePreset, o as effectiveOrder, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-m3CdTGSl.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 { t as registerCoreNodes } from "./register-Dl_ixIJe.js";
@@ -210,7 +210,18 @@ var Node3D = class extends Node {
210
210
  1
211
211
  ] },
212
212
  visible: { default: true },
213
- renderOrder: { default: 0 }
213
+ renderOrder: { default: 0 },
214
+ orderGroup: {
215
+ default: "default",
216
+ options: [
217
+ "background",
218
+ "terrain",
219
+ "default",
220
+ "characters",
221
+ "effects",
222
+ "overlay"
223
+ ]
224
+ }
214
225
  };
215
226
  position = [
216
227
  0,
@@ -242,6 +253,12 @@ var Node3D = class extends Node {
242
253
  * materials — three sorts the transparent pass by renderOrder, then depth.
243
254
  * Pairs with named scene constants (e.g. `{"@const": "UI"}`) for sorting tiers. */
244
255
  renderOrder = 0;
256
+ /** Named draw-order band; `renderOrder` is the fine offset inside it. */
257
+ orderGroup = "default";
258
+ /** What three actually sorts by: band base + renderOrder. */
259
+ get effectiveRenderOrder() {
260
+ return effectiveOrder(this.orderGroup, this.renderOrder);
261
+ }
245
262
  _object3D = null;
246
263
  /**
247
264
  * @internal Fixed-step render interpolation. A physics body fills these with
@@ -275,7 +292,7 @@ var Node3D = class extends Node {
275
292
  o.rotation.set(MathUtils.degToRad(this.rotation[0] ?? 0), MathUtils.degToRad(this.rotation[1] ?? 0), MathUtils.degToRad(this.rotation[2] ?? 0));
276
293
  o.scale.set(this.scale[0] ?? 1, this.scale[1] ?? 1, this.scale[2] ?? 1);
277
294
  o.visible = this.visible;
278
- o.renderOrder = this.renderOrder;
295
+ o.renderOrder = this.effectiveRenderOrder;
279
296
  }
280
297
  free() {
281
298
  super.free();
@@ -1139,8 +1156,20 @@ const MAX_RESOLUTION = 128;
1139
1156
  * real numbers off `heightAt`.
1140
1157
  */
1141
1158
  var Terrain3D = class extends Node3D {
1159
+ orderGroup = "terrain";
1142
1160
  static typeName = "Terrain3D";
1143
1161
  static props = {
1162
+ orderGroup: {
1163
+ default: "terrain",
1164
+ options: [
1165
+ "background",
1166
+ "terrain",
1167
+ "default",
1168
+ "characters",
1169
+ "effects",
1170
+ "overlay"
1171
+ ]
1172
+ },
1144
1173
  size: { default: [200, 200] },
1145
1174
  maxHeight: { default: 28 },
1146
1175
  seed: { default: 1 },
@@ -5820,9 +5849,21 @@ const PX_TO_M = .01;
5820
5849
  * tilts emission out of the plane too).
5821
5850
  */
5822
5851
  var Particles3D = class Particles3D extends Node3D {
5852
+ orderGroup = "effects";
5823
5853
  static typeName = "Particles3D";
5824
5854
  static signals = ["finished"];
5825
5855
  static props = {
5856
+ orderGroup: {
5857
+ default: "effects",
5858
+ options: [
5859
+ "background",
5860
+ "terrain",
5861
+ "default",
5862
+ "characters",
5863
+ "effects",
5864
+ "overlay"
5865
+ ]
5866
+ },
5826
5867
  preset: {
5827
5868
  default: "custom",
5828
5869
  options: ["custom", ...PARTICLE_PRESET_NAMES]
package/dist/test.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { c as JsonValue, i as SceneJson } from "./schema-CcoWb32N.js";
2
- import { O as LogEntry, T as Node, n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-CWhW3oa6.js";
3
- import { t as LoadSceneOptions } from "./loader-D2u0fVW2.js";
2
+ import { T as LogEntry, Z as Node, n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-q3cejJgs.js";
3
+ import { t as LoadSceneOptions } from "./loader-DnLMMRy8.js";
4
4
  import { t as IncantoError } from "./errors-BMFaY68Q.js";
5
5
 
6
6
  //#region src/test/index.d.ts