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
package/dist/2d.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { s as JsonObject } from "./schema-CcoWb32N.js";
2
- import { C as RendererStats, S as GameStats, T as Node, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-CWhW3oa6.js";
3
- import { t as LoadSceneOptions } from "./loader-D2u0fVW2.js";
2
+ import { C as RendererStats, S as GameStats, Z as Node, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-q3cejJgs.js";
3
+ import { t as LoadSceneOptions } from "./loader-DnLMMRy8.js";
4
4
  import { t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
5
5
  import { Group, Mesh, Object3D, Scene, Texture } from "three";
6
6
  import * as RapierNs from "@dimforge/rapier2d-compat";
@@ -57,6 +57,10 @@ declare class Node2D extends Node {
57
57
  scale: number[];
58
58
  /** Draw order among 2D drawables (higher = on top); matches 3D `renderOrder`. */
59
59
  renderOrder: number;
60
+ /** Named draw-order band; `renderOrder` is the fine offset inside it. */
61
+ orderGroup: string;
62
+ /** What three actually sorts by: band base + renderOrder. */
63
+ get effectiveRenderOrder(): number;
60
64
  visible: boolean;
61
65
  private _object2D;
62
66
  /** @internal The backing three object (lazily created). */
@@ -507,6 +511,7 @@ declare class Label extends Node2D {
507
511
  * Simulation is deterministic under the engine seed.
508
512
  */
509
513
  declare class Particles2D extends Node2D {
514
+ override orderGroup: string;
510
515
  static override readonly typeName: string;
511
516
  static override readonly signals: readonly string[];
512
517
  static override readonly props: PropSchema;
@@ -650,6 +655,8 @@ declare class Renderer2D {
650
655
  private readonly canvas;
651
656
  constructor(opts: Renderer2DOptions);
652
657
  private readonly debugLines;
658
+ private readonly selectionLines;
659
+ private syncSelectionOutline;
653
660
  private syncDebugLines;
654
661
  private render;
655
662
  private lastViewport;
package/dist/2d.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
- import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-B_sW_eiE.js";
3
- import { a as ColorRect2D, c as AnimatedSprite2D, d as Area2D, f as CharacterBody2D, g as Node2D, h as StaticBody2D, i as Label, l as Sprite2D, m as RigidBody2D, n as UILayer, o as CharacterController2D, p as PhysicsBody2D, r as Particles2D, s as Camera2D, t as registerNodes2D, u as Joint2D } from "./register-BJCfuuZ2.js";
4
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-Cgli1aju.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-DuDkqnjl.js";
3
+ import { a as ColorRect2D, c as AnimatedSprite2D, d as Area2D, f as CharacterBody2D, g as Node2D, h as StaticBody2D, i as Label, l as Sprite2D, m as RigidBody2D, n as UILayer, o as CharacterController2D, p as PhysicsBody2D, r as Particles2D, s as Camera2D, t as registerNodes2D, u as Joint2D } from "./register-Cl3pAxX-.js";
4
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-CZM5Y90X.js";
5
5
  //#region src/2d/library-sprite.ts
6
6
  /**
7
7
  * Turn a library sprite-animation JSON into a scene-ready spritesheet asset
package/dist/3d.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { s as JsonObject } from "./schema-CcoWb32N.js";
2
- import { C as RendererStats, S as GameStats, T as Node, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-CWhW3oa6.js";
3
- import { t as LoadSceneOptions } from "./loader-D2u0fVW2.js";
2
+ import { C as RendererStats, S as GameStats, Z as Node, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-q3cejJgs.js";
3
+ import { t as LoadSceneOptions } from "./loader-DnLMMRy8.js";
4
4
  import { t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
5
- import { r as SpatialPose } from "./audio-player-DkBqRTs4.js";
5
+ import { r as SpatialPose } from "./audio-player-C3bH_eZ5.js";
6
6
  import { AnimationClip, BufferGeometry, Color, DirectionalLight, InstancedMesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from "three";
7
7
  import { VRM } from "@pixiv/three-vrm";
8
8
  import { Sky } from "three/examples/jsm/objects/Sky.js";
@@ -152,6 +152,10 @@ declare class Node3D extends Node {
152
152
  * materials — three sorts the transparent pass by renderOrder, then depth.
153
153
  * Pairs with named scene constants (e.g. `{"@const": "UI"}`) for sorting tiers. */
154
154
  renderOrder: number;
155
+ /** Named draw-order band; `renderOrder` is the fine offset inside it. */
156
+ orderGroup: string;
157
+ /** What three actually sorts by: band base + renderOrder. */
158
+ get effectiveRenderOrder(): number;
155
159
  private _object3D;
156
160
  /**
157
161
  * @internal Fixed-step render interpolation. A physics body fills these with
@@ -1291,6 +1295,7 @@ declare class ModelInstance3D extends Node3D {
1291
1295
  * tilts emission out of the plane too).
1292
1296
  */
1293
1297
  declare class Particles3D extends Node3D {
1298
+ override orderGroup: string;
1294
1299
  static override readonly typeName: string;
1295
1300
  static override readonly signals: readonly string[];
1296
1301
  static override readonly props: PropSchema;
@@ -1486,6 +1491,7 @@ declare function terrainThemeLayers(theme: TerrainTheme, textureBase: string): T
1486
1491
  * real numbers off `heightAt`.
1487
1492
  */
1488
1493
  declare class Terrain3D extends Node3D {
1494
+ override orderGroup: string;
1489
1495
  static override readonly typeName: string;
1490
1496
  static override readonly props: PropSchema;
1491
1497
  /** [width, depth] extent in meters, centered on the node. */
@@ -1963,6 +1969,8 @@ declare class Renderer3D {
1963
1969
  private bloomCompositeUniforms;
1964
1970
  constructor(opts: Renderer3DOptions);
1965
1971
  private readonly debugLines;
1972
+ private readonly selectionLines;
1973
+ private syncSelectionOutline;
1966
1974
  private syncDebugLines;
1967
1975
  private render;
1968
1976
  /**
package/dist/3d.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-DkbZCNaV.js";
2
- import { A as StaticBody3D, C as TERRAIN_THEMES, D as CharacterBody3D, E as Area3D, F as keyboardIntensity, I as movementState, L as rigPose, N as QUARTER_PITCH, O as PhysicsBody3D, P as cameraRelative, S as DEFAULT_TERRAIN_TEXTURE_BASE, T as Joint3D, _ as FLOWER_VARIETIES, a as VoxelGrid3D, b as Billboard3D, c as ModelInstance3D, d as DirectionalLight3D, f as OmniLight3D, g as resolveFlowerDensity, h as Flowers3D, i as VOXEL_PALETTE, j as Node3D, k as RigidBody3D, l as LoftMesh3D, m as DENSITY_PRESETS, n as Water3D, o as Tree3D, p as Foliage3D, r as WATER_MAX_RIPPLES, s as Particles3D, t as registerNodes3D, u as MeshInstance3D, v as CharacterController3D, w as terrainThemeLayers, x as Terrain3D, y as Camera3D } from "./register-Dd7Juujf.js";
1
+ import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-rFulaS3s.js";
2
+ import { A as StaticBody3D, C as TERRAIN_THEMES, D as CharacterBody3D, E as Area3D, F as keyboardIntensity, I as movementState, L as rigPose, N as QUARTER_PITCH, O as PhysicsBody3D, P as cameraRelative, S as DEFAULT_TERRAIN_TEXTURE_BASE, T as Joint3D, _ as FLOWER_VARIETIES, a as VoxelGrid3D, b as Billboard3D, c as ModelInstance3D, d as DirectionalLight3D, f as OmniLight3D, g as resolveFlowerDensity, h as Flowers3D, i as VOXEL_PALETTE, j as Node3D, k as RigidBody3D, l as LoftMesh3D, m as DENSITY_PRESETS, n as Water3D, o as Tree3D, p as Foliage3D, r as WATER_MAX_RIPPLES, s as Particles3D, t as registerNodes3D, u as MeshInstance3D, v as CharacterController3D, w as terrainThemeLayers, x as Terrain3D, y as Camera3D } from "./register-CpXcMiEk.js";
3
3
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CroQPEER.js";
4
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CBAQ12LY.js";
4
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DT5e8izo.js";
5
5
  export { Area3D, AssetStore3D, Billboard3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_MAX_RIPPLES, Water3D, buildHeightmap, cameraRelative, createGame3D, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers };
@@ -1,4 +1,4 @@
1
- import { F as Listener, T as Node, l as PropSchema } from "./behavior-CWhW3oa6.js";
1
+ import { M as Listener, Z as Node, l as PropSchema } from "./behavior-q3cejJgs.js";
2
2
 
3
3
  //#region src/core/nodes/audio-player.d.ts
4
4
  /**
@@ -1,5 +1,68 @@
1
1
  import { a as Rng, c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CcoWb32N.js";
2
2
 
3
+ //#region src/core/scene-tree.d.ts
4
+ /**
5
+ * Owns a node tree and drives its lifecycle:
6
+ *
7
+ * - `setRoot` → onEnterTree parent-first, then onReady children-first (once per instance)
8
+ * - `update`/`fixedUpdate` → parent-first traversal, then flush of queued frees
9
+ * - group queries across attached nodes
10
+ *
11
+ * Headless by design — tests step it manually; the render loop (M2) calls it.
12
+ */
13
+ declare class SceneTree {
14
+ private _root;
15
+ private _engine;
16
+ private readonly freeQueue;
17
+ /**
18
+ * name → attached nodes with that name. Maintained by Node enter/exit/rename
19
+ * so `%name` targeting and root-level getNodesByName are O(1) — behaviors
20
+ * resolve targets every frame and a full-tree walk per chaser melted horde
21
+ * scenes (N chasers × whole tree, 60×/s).
22
+ */
23
+ private readonly _nameIndex;
24
+ /**
25
+ * Bumped whenever ANY node attaches or detaches — cheap "did the tree
26
+ * change shape?" check for per-step body gathers and similar caches.
27
+ */
28
+ _structureVersion: number;
29
+ private _frameId;
30
+ /**
31
+ * Monotonic update-frame counter — bumped once per `update()`. Per-frame
32
+ * caches (e.g. the 3d grass-bender body gather) key off this so they rebuild
33
+ * at most once a frame regardless of node visitation order.
34
+ */
35
+ get frameId(): number;
36
+ /** @internal Node attach hook. */
37
+ _indexName(node: Node): void;
38
+ /** @internal Node detach/rename hook (`name` = the entry to remove). */
39
+ _unindexName(node: Node, name?: string): void;
40
+ /** @internal Every ATTACHED node named `name` (undefined = none). */
41
+ _nodesNamed(name: string): ReadonlySet<Node> | undefined;
42
+ /**
43
+ * @internal Opaque per-frame scratch the 3d layer parks its shared moving-body
44
+ * snapshot on (kept here so it is per-tree-instance, never a module global —
45
+ * core stays three-free, the 3d resolver owns the shape).
46
+ */
47
+ _frameScratch: unknown;
48
+ get root(): Node | null;
49
+ /** The engine driving this tree (set by Engine.setScene), or null. */
50
+ get engine(): Engine | null;
51
+ /** @internal */
52
+ _setEngine(engine: Engine | null): void;
53
+ setRoot(node: Node): void;
54
+ update(dt: number): void;
55
+ fixedUpdate(dt: number): void;
56
+ getNodesInGroup(group: string): Node[];
57
+ /** Call `method(...args)` on every group member that implements it. */
58
+ callGroup(group: string, method: string, ...args: unknown[]): void;
59
+ /** @internal */
60
+ _queueFree(node: Node): void;
61
+ /** @internal Called by Node.free(): a freed root must not be re-drivable. */
62
+ _detachRoot(node: Node): void;
63
+ private flushFreeQueue;
64
+ }
65
+ //#endregion
3
66
  //#region src/core/signal.d.ts
4
67
  /**
5
68
  * Minimal typed observer used for every engine event (Godot signal semantics).
@@ -20,6 +83,116 @@ declare class Signal<Args extends unknown[] = unknown[]> {
20
83
  get connectionCount(): number;
21
84
  }
22
85
  //#endregion
86
+ //#region src/core/node.d.ts
87
+ /** Lifecycle hooks a SceneTree drives. Wired in scene-tree.ts. */
88
+ interface NodeLifecycle {
89
+ onEnterTree(): void;
90
+ onReady(): void;
91
+ onExitTree(): void;
92
+ update(dt: number): void;
93
+ fixedUpdate(dt: number): void;
94
+ }
95
+ /**
96
+ * Base class of everything in an Incanto scene (Godot's Node model).
97
+ *
98
+ * Pure data + tree structure: no rendering, no DOM, no three.js — renderer
99
+ * adapters subscribe from the outside.
100
+ */
101
+ declare class Node implements NodeLifecycle {
102
+ static readonly typeName: string;
103
+ /**
104
+ * Signals this node type can emit, declared statically (merged up the class
105
+ * hierarchy). A behavior's `static signals` are declared onto its node at
106
+ * load. Emitting or subscribing an UNDECLARED signal is a hard error —
107
+ * a typo'd signal name must fail loudly, never silently never-fire.
108
+ */
109
+ static readonly signals?: readonly string[];
110
+ private _name;
111
+ private _parent;
112
+ private readonly _children;
113
+ private readonly _groups;
114
+ private readonly _signals;
115
+ private _declared;
116
+ private _tree;
117
+ private _ready;
118
+ /**
119
+ * Optional STABLE identifier (scene JSON `uid`) — unlike names (unique only
120
+ * among siblings) a uid is unique across the whole scene, so scripts and
121
+ * tools can address a node no matter where it moves.
122
+ */
123
+ uid: string | null;
124
+ /** Free-form JSON identity for game logic (e.g. `{kind: 'ITEM', value: 10}`). */
125
+ tags: Record<string, unknown>;
126
+ /** Behavior attachment blob from scene JSON (resolved by the loader). */
127
+ script: JsonObject | null;
128
+ /** The resolved behavior instance (set by the loader from `script`). */
129
+ behavior: Behavior | null;
130
+ /** Replication config blob from scene JSON (interpreted in M6; preserved until then). */
131
+ network: JsonObject | null;
132
+ constructor(name?: string);
133
+ get name(): string;
134
+ set name(value: string);
135
+ get parent(): Node | null;
136
+ get children(): readonly Node[];
137
+ get groups(): ReadonlySet<string>;
138
+ /** The SceneTree this node is attached to, or null while detached. */
139
+ get tree(): SceneTree | null;
140
+ /** Whether onReady has run (it runs at most once per instance). */
141
+ get isReady(): boolean;
142
+ addChild<T extends Node>(child: T): T;
143
+ removeChild(child: Node): void;
144
+ reparent(newParent: Node): void;
145
+ findChild(name: string, recursive?: boolean): Node | null;
146
+ /** Topmost ancestor (the node itself when detached). */
147
+ getRoot(): Node;
148
+ /** Depth-first search of THIS subtree for the node carrying `uid`. */
149
+ getNodeByUid(uid: string): Node | null;
150
+ /** Every node in THIS subtree named `name` — names repeat, so a list. */
151
+ getNodesByName(name: string): Node[];
152
+ getPath(): string;
153
+ getNode(path: string): Node;
154
+ getNodeOrNull(path: string): Node | null;
155
+ private resolve;
156
+ addToGroup(group: string): void;
157
+ removeFromGroup(group: string): void;
158
+ isInGroup(group: string): boolean;
159
+ private declaredSignals;
160
+ /** Declare an ad-hoc signal on THIS instance (static `signals` covers types). */
161
+ declareSignal(name: string): void;
162
+ /** Every signal this instance may emit (static + behavior + ad-hoc). */
163
+ declaredSignalNames(): string[];
164
+ private assertDeclared;
165
+ /** Get the named DECLARED signal (creating its Signal object on demand). */
166
+ signal(name: string): Signal<unknown[]>;
167
+ on(signal: string, fn: SignalListener<unknown[]>, opts?: {
168
+ once?: boolean;
169
+ }): () => void;
170
+ off(signal: string, fn: SignalListener<unknown[]>): void;
171
+ emit(signal: string, ...args: unknown[]): void;
172
+ /**
173
+ * Defer destruction to the end of the current update pass (flushed by the
174
+ * SceneTree). Frees immediately when detached from any tree.
175
+ */
176
+ queueFree(): void;
177
+ /** Immediately detach and tear down this node and its children. */
178
+ free(): void;
179
+ /** @internal */
180
+ _propagateEnterTree(tree: SceneTree): void;
181
+ /** @internal */
182
+ _propagateReady(): void;
183
+ /** @internal */
184
+ _propagateExitTree(): void;
185
+ /** @internal */
186
+ _propagateUpdate(dt: number): void;
187
+ /** @internal */
188
+ _propagateFixedUpdate(dt: number): void;
189
+ onEnterTree(): void;
190
+ onReady(): void;
191
+ onExitTree(): void;
192
+ update(_dt: number): void;
193
+ fixedUpdate(_dt: number): void;
194
+ }
195
+ //#endregion
23
196
  //#region src/core/audio/buses.d.ts
24
197
  /** The two volume buses every sound routes through (plus the global `master`). */
25
198
  type BusName = "sfx" | "music";
@@ -477,179 +650,6 @@ declare class LogManager {
477
650
  private push;
478
651
  }
479
652
  //#endregion
480
- //#region src/core/scene-tree.d.ts
481
- /**
482
- * Owns a node tree and drives its lifecycle:
483
- *
484
- * - `setRoot` → onEnterTree parent-first, then onReady children-first (once per instance)
485
- * - `update`/`fixedUpdate` → parent-first traversal, then flush of queued frees
486
- * - group queries across attached nodes
487
- *
488
- * Headless by design — tests step it manually; the render loop (M2) calls it.
489
- */
490
- declare class SceneTree {
491
- private _root;
492
- private _engine;
493
- private readonly freeQueue;
494
- /**
495
- * name → attached nodes with that name. Maintained by Node enter/exit/rename
496
- * so `%name` targeting and root-level getNodesByName are O(1) — behaviors
497
- * resolve targets every frame and a full-tree walk per chaser melted horde
498
- * scenes (N chasers × whole tree, 60×/s).
499
- */
500
- private readonly _nameIndex;
501
- /**
502
- * Bumped whenever ANY node attaches or detaches — cheap "did the tree
503
- * change shape?" check for per-step body gathers and similar caches.
504
- */
505
- _structureVersion: number;
506
- private _frameId;
507
- /**
508
- * Monotonic update-frame counter — bumped once per `update()`. Per-frame
509
- * caches (e.g. the 3d grass-bender body gather) key off this so they rebuild
510
- * at most once a frame regardless of node visitation order.
511
- */
512
- get frameId(): number;
513
- /** @internal Node attach hook. */
514
- _indexName(node: Node): void;
515
- /** @internal Node detach/rename hook (`name` = the entry to remove). */
516
- _unindexName(node: Node, name?: string): void;
517
- /** @internal Every ATTACHED node named `name` (undefined = none). */
518
- _nodesNamed(name: string): ReadonlySet<Node> | undefined;
519
- /**
520
- * @internal Opaque per-frame scratch the 3d layer parks its shared moving-body
521
- * snapshot on (kept here so it is per-tree-instance, never a module global —
522
- * core stays three-free, the 3d resolver owns the shape).
523
- */
524
- _frameScratch: unknown;
525
- get root(): Node | null;
526
- /** The engine driving this tree (set by Engine.setScene), or null. */
527
- get engine(): Engine | null;
528
- /** @internal */
529
- _setEngine(engine: Engine | null): void;
530
- setRoot(node: Node): void;
531
- update(dt: number): void;
532
- fixedUpdate(dt: number): void;
533
- getNodesInGroup(group: string): Node[];
534
- /** Call `method(...args)` on every group member that implements it. */
535
- callGroup(group: string, method: string, ...args: unknown[]): void;
536
- /** @internal */
537
- _queueFree(node: Node): void;
538
- /** @internal Called by Node.free(): a freed root must not be re-drivable. */
539
- _detachRoot(node: Node): void;
540
- private flushFreeQueue;
541
- }
542
- //#endregion
543
- //#region src/core/node.d.ts
544
- /** Lifecycle hooks a SceneTree drives. Wired in scene-tree.ts. */
545
- interface NodeLifecycle {
546
- onEnterTree(): void;
547
- onReady(): void;
548
- onExitTree(): void;
549
- update(dt: number): void;
550
- fixedUpdate(dt: number): void;
551
- }
552
- /**
553
- * Base class of everything in an Incanto scene (Godot's Node model).
554
- *
555
- * Pure data + tree structure: no rendering, no DOM, no three.js — renderer
556
- * adapters subscribe from the outside.
557
- */
558
- declare class Node implements NodeLifecycle {
559
- static readonly typeName: string;
560
- /**
561
- * Signals this node type can emit, declared statically (merged up the class
562
- * hierarchy). A behavior's `static signals` are declared onto its node at
563
- * load. Emitting or subscribing an UNDECLARED signal is a hard error —
564
- * a typo'd signal name must fail loudly, never silently never-fire.
565
- */
566
- static readonly signals?: readonly string[];
567
- private _name;
568
- private _parent;
569
- private readonly _children;
570
- private readonly _groups;
571
- private readonly _signals;
572
- private _declared;
573
- private _tree;
574
- private _ready;
575
- /**
576
- * Optional STABLE identifier (scene JSON `uid`) — unlike names (unique only
577
- * among siblings) a uid is unique across the whole scene, so scripts and
578
- * tools can address a node no matter where it moves.
579
- */
580
- uid: string | null;
581
- /** Free-form JSON identity for game logic (e.g. `{kind: 'ITEM', value: 10}`). */
582
- tags: Record<string, unknown>;
583
- /** Behavior attachment blob from scene JSON (resolved by the loader). */
584
- script: JsonObject | null;
585
- /** The resolved behavior instance (set by the loader from `script`). */
586
- behavior: Behavior | null;
587
- /** Replication config blob from scene JSON (interpreted in M6; preserved until then). */
588
- network: JsonObject | null;
589
- constructor(name?: string);
590
- get name(): string;
591
- set name(value: string);
592
- get parent(): Node | null;
593
- get children(): readonly Node[];
594
- get groups(): ReadonlySet<string>;
595
- /** The SceneTree this node is attached to, or null while detached. */
596
- get tree(): SceneTree | null;
597
- /** Whether onReady has run (it runs at most once per instance). */
598
- get isReady(): boolean;
599
- addChild<T extends Node>(child: T): T;
600
- removeChild(child: Node): void;
601
- reparent(newParent: Node): void;
602
- findChild(name: string, recursive?: boolean): Node | null;
603
- /** Topmost ancestor (the node itself when detached). */
604
- getRoot(): Node;
605
- /** Depth-first search of THIS subtree for the node carrying `uid`. */
606
- getNodeByUid(uid: string): Node | null;
607
- /** Every node in THIS subtree named `name` — names repeat, so a list. */
608
- getNodesByName(name: string): Node[];
609
- getPath(): string;
610
- getNode(path: string): Node;
611
- getNodeOrNull(path: string): Node | null;
612
- private resolve;
613
- addToGroup(group: string): void;
614
- removeFromGroup(group: string): void;
615
- isInGroup(group: string): boolean;
616
- private declaredSignals;
617
- /** Declare an ad-hoc signal on THIS instance (static `signals` covers types). */
618
- declareSignal(name: string): void;
619
- /** Every signal this instance may emit (static + behavior + ad-hoc). */
620
- declaredSignalNames(): string[];
621
- private assertDeclared;
622
- /** Get the named DECLARED signal (creating its Signal object on demand). */
623
- signal(name: string): Signal<unknown[]>;
624
- on(signal: string, fn: SignalListener<unknown[]>, opts?: {
625
- once?: boolean;
626
- }): () => void;
627
- off(signal: string, fn: SignalListener<unknown[]>): void;
628
- emit(signal: string, ...args: unknown[]): void;
629
- /**
630
- * Defer destruction to the end of the current update pass (flushed by the
631
- * SceneTree). Frees immediately when detached from any tree.
632
- */
633
- queueFree(): void;
634
- /** Immediately detach and tear down this node and its children. */
635
- free(): void;
636
- /** @internal */
637
- _propagateEnterTree(tree: SceneTree): void;
638
- /** @internal */
639
- _propagateReady(): void;
640
- /** @internal */
641
- _propagateExitTree(): void;
642
- /** @internal */
643
- _propagateUpdate(dt: number): void;
644
- /** @internal */
645
- _propagateFixedUpdate(dt: number): void;
646
- onEnterTree(): void;
647
- onReady(): void;
648
- onExitTree(): void;
649
- update(_dt: number): void;
650
- fixedUpdate(_dt: number): void;
651
- }
652
- //#endregion
653
653
  //#region src/core/scene/scene.d.ts
654
654
  /**
655
655
  * A loaded, live scene: the node tree plus everything needed to round-trip
@@ -773,6 +773,24 @@ declare class Engine {
773
773
  * timers, behaviors all breathe together. See `gameplay` `hitStop()`.
774
774
  */
775
775
  timeScale: number;
776
+ /**
777
+ * The node the dev overlay has selected (renderers draw its bounding box
778
+ * as an orange outline in the game view so you can SEE what you picked).
779
+ * Null when nothing is selected; cleared automatically when it leaves the
780
+ * tree. Set by the debug overlay — games normally never touch this.
781
+ */
782
+ debugSelection: Node | null;
783
+ private _time;
784
+ private _unscaledTime;
785
+ /**
786
+ * Elapsed GAME time in seconds since the scene started — the sum of every
787
+ * scaled dt (freezes at timeScale 0, crawls in slow motion). Unity's
788
+ * `Time.time`. Resets on `setScene`.
789
+ */
790
+ get time(): number;
791
+ /** Elapsed REAL time in seconds since the scene started (ignores timeScale) —
792
+ * UI animations that must keep moving during slow-mo/pause read this. */
793
+ get unscaledTime(): number;
776
794
  constructor(opts?: EngineOptions);
777
795
  get scene(): Scene | null;
778
796
  /** Replace the active scene. The previous scene's root is freed. */
@@ -902,4 +920,4 @@ declare function registeredBehaviors(): string[];
902
920
  /** Test isolation helper. */
903
921
  declare function clearBehaviors(): void;
904
922
  //#endregion
905
- export { BusName as $, LogManager as A, spatialGain as B, RendererStats as C, SceneTree as D, NodeLifecycle as E, Listener as F, SfxWave as G, SFX_PRESETS as H, ROLLOFF_MODELS as I, MusicBackend as J, SynthOptions as K, RolloffModel as L, SfxEngine as M, SfxPlayOptions as N, LogEntry as O, isAudioContextAvailable as P, AudioBuses as Q, SpatialParams as R, GameStats as S, Node as T, SFX_PRESET_NAMES as U, spatialPan as V, SfxParams as W, MusicTrack as X, MusicManager as Y, PlayMusicOptions as Z, registeredTypes as _, registerBehavior as a, Scheduler as b, PropDef as c, createNode as d, Signal as et, getNodeSchema as f, registerNode as g, mergeStaticSignals as h, getBehavior as i, InputMap as j, LogLevel as k, PropSchema as l, getNodeType as m, BehaviorCtor as n, registeredBehaviors as o, getNodeSignals as p, synthSfx as q, clearBehaviors as r, NodeCtor as s, Behavior as t, SignalListener as tt, clearRegistry as u, Engine as v, Scene as w, EngineStats as x, EngineOptions as y, Vec3 as z };
923
+ export { Signal as $, SfxPlayOptions as A, SFX_PRESET_NAMES as B, RendererStats as C, LogManager as D, LogLevel as E, SpatialParams as F, MusicBackend as G, SfxWave as H, Vec3 as I, PlayMusicOptions as J, MusicManager as K, spatialGain as L, Listener as M, ROLLOFF_MODELS as N, InputMap as O, RolloffModel as P, NodeLifecycle as Q, spatialPan as R, GameStats as S, LogEntry as T, SynthOptions as U, SfxParams as V, synthSfx as W, BusName as X, AudioBuses as Y, Node as Z, registeredTypes as _, registerBehavior as a, Scheduler as b, PropDef as c, createNode as d, SignalListener as et, getNodeSchema as f, registerNode as g, mergeStaticSignals as h, getBehavior as i, isAudioContextAvailable as j, SfxEngine as k, PropSchema as l, getNodeType as m, BehaviorCtor as n, registeredBehaviors as o, getNodeSignals as p, MusicTrack as q, clearBehaviors as r, NodeCtor as s, Behavior as t, SceneTree as tt, clearRegistry as u, Engine as v, Scene as w, EngineStats as x, EngineOptions as y, SFX_PRESETS as z };
@@ -1,13 +1,13 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { _ as registerBehavior, n as loadScene, o as computeViewport, s as resolveViewport } 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
- import { g as Node2D, n as UILayer, p as PhysicsBody2D, s as Camera2D, t as registerNodes2D } from "./register-BJCfuuZ2.js";
8
+ import { g as Node2D, n as UILayer, p as PhysicsBody2D, s as Camera2D, t as registerNodes2D } from "./register-Cl3pAxX-.js";
9
9
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
10
- import { n as enablePhysics2D } from "./physics-2d-Cgli1aju.js";
10
+ import { n as enablePhysics2D } from "./physics-2d-CZM5Y90X.js";
11
11
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
12
12
  //#region src/2d/assets.ts
13
13
  /**
@@ -101,6 +101,58 @@ function worldFromScreen(view, sx, sy) {
101
101
  };
102
102
  }
103
103
  //#endregion
104
+ //#region src/2d/selection-outline.ts
105
+ /** 2D twin of the 3D selection outline: a world-space (px, y-down) rectangle
106
+ * around the selected node's rendered extent, or a marker square. */
107
+ const box = new Box3();
108
+ const size = new Vector3();
109
+ const MARKER_HALF = 12;
110
+ /** 4 rect edges = 8 points × xy. */
111
+ const OUT = new Float32Array(16);
112
+ function selectionOutline2D(node) {
113
+ if (!(node instanceof Node2D)) return null;
114
+ const obj = node._ensureObject2D();
115
+ obj.updateWorldMatrix(true, true);
116
+ box.setFromObject(obj);
117
+ box.getSize(size);
118
+ let minX;
119
+ let minY;
120
+ let maxX;
121
+ let maxY;
122
+ if (!Number.isFinite(size.x) || size.x === 0 && size.y === 0) {
123
+ const p = new Vector3().setFromMatrixPosition(obj.matrixWorld);
124
+ minX = p.x - MARKER_HALF;
125
+ maxX = p.x + MARKER_HALF;
126
+ minY = p.y - MARKER_HALF;
127
+ maxY = p.y + MARKER_HALF;
128
+ } else {
129
+ minX = box.min.x - 2;
130
+ maxX = box.max.x + 2;
131
+ minY = box.min.y - 2;
132
+ maxY = box.max.y + 2;
133
+ }
134
+ const pts = [
135
+ minX,
136
+ minY,
137
+ maxX,
138
+ minY,
139
+ maxX,
140
+ minY,
141
+ maxX,
142
+ maxY,
143
+ maxX,
144
+ maxY,
145
+ minX,
146
+ maxY,
147
+ minX,
148
+ maxY,
149
+ minX,
150
+ minY
151
+ ];
152
+ OUT.set(pts);
153
+ return OUT;
154
+ }
155
+ //#endregion
104
156
  //#region src/2d/sync.ts
105
157
  function createSync2DScratch() {
106
158
  return {
@@ -217,14 +269,44 @@ var Renderer2D = class {
217
269
  });
218
270
  this.webgl.setPixelRatio(rendering.pixelRatio);
219
271
  this.webgl.info.autoReset = false;
220
- this.debugLines = new LineSegments(new BufferGeometry(), new LineBasicMaterial({ color: "#00ff6e" }));
272
+ this.debugLines = new LineSegments(new BufferGeometry(), new LineBasicMaterial({
273
+ color: "#00ff6e",
274
+ transparent: true,
275
+ depthTest: false
276
+ }));
221
277
  this.debugLines.frustumCulled = false;
222
278
  this.debugLines.renderOrder = 9999;
223
279
  this.debugLines.visible = false;
224
280
  this.worldScene.add(this.debugLines);
281
+ this.selectionLines = new LineSegments(new BufferGeometry(), new LineBasicMaterial({
282
+ color: "#ffb020",
283
+ transparent: true,
284
+ depthTest: false
285
+ }));
286
+ this.selectionLines.frustumCulled = false;
287
+ this.selectionLines.renderOrder = 1e4;
288
+ this.selectionLines.visible = false;
289
+ this.worldScene.add(this.selectionLines);
225
290
  this.disconnect = this.engine.updated.connect(() => this.render());
226
291
  }
227
292
  debugLines;
293
+ selectionLines;
294
+ syncSelectionOutline() {
295
+ const node = this.engine.debugSelection;
296
+ if (node && node.tree !== this.engine.scene?.tree) this.engine.debugSelection = null;
297
+ const current = this.engine.debugSelection;
298
+ const vertices = current ? selectionOutline2D(current) : null;
299
+ this.selectionLines.visible = vertices !== null;
300
+ if (!vertices) return;
301
+ const xyz = new Float32Array(vertices.length / 2 * 3);
302
+ for (let i = 0, j = 0; i < vertices.length; i += 2, j += 3) {
303
+ xyz[j] = vertices[i];
304
+ xyz[j + 1] = vertices[i + 1];
305
+ xyz[j + 2] = 0;
306
+ }
307
+ this.selectionLines.geometry.setAttribute("position", new BufferAttribute(xyz, 3));
308
+ this.selectionLines.geometry.getAttribute("position").needsUpdate = true;
309
+ }
228
310
  syncDebugLines() {
229
311
  let vertices = null;
230
312
  for (const source of debugSources("2d")) {
@@ -246,6 +328,7 @@ var Renderer2D = class {
246
328
  if (!scene) return;
247
329
  this.webgl.info.reset();
248
330
  this.syncDebugLines();
331
+ this.syncSelectionOutline();
249
332
  if (scene.assets && !this.loadedAssetScenes.has(scene)) {
250
333
  this.assets.load(scene.assets);
251
334
  this.loadedAssetScenes.add(scene);