incanto 0.1.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 (138) hide show
  1. package/LICENSE +30 -0
  2. package/README.md +36 -0
  3. package/THIRD-PARTY-NOTICES.md +88 -0
  4. package/assets/audio/attacked.mp3 +0 -0
  5. package/assets/audio/explosion.mp3 +0 -0
  6. package/assets/audio/gold_loot.mp3 +0 -0
  7. package/assets/audio/heal.mp3 +0 -0
  8. package/assets/audio/hit_metal_bang.mp3 +0 -0
  9. package/assets/audio/ice_spear.mp3 +0 -0
  10. package/assets/audio/monster_died.mp3 +0 -0
  11. package/assets/audio/slash.mp3 +0 -0
  12. package/assets/audio/smite.mp3 +0 -0
  13. package/assets/audio/spells_cast.mp3 +0 -0
  14. package/assets/audio/ui_click.wav +0 -0
  15. package/assets/audio/walk.mp3 +0 -0
  16. package/assets/catalog.json +390 -0
  17. package/assets/characters/2dbasic.json +41 -0
  18. package/assets/characters/2dbasic.png +0 -0
  19. package/assets/characters/ghost.json +46 -0
  20. package/assets/characters/ghost.png +0 -0
  21. package/assets/characters/goblin.json +40 -0
  22. package/assets/characters/goblin.png +0 -0
  23. package/assets/characters/medieval-knight.json +41 -0
  24. package/assets/characters/medieval-knight.png +0 -0
  25. package/assets/effects/swoosh.png +0 -0
  26. package/assets/items/box.png +0 -0
  27. package/assets/items/buff_potion.png +0 -0
  28. package/assets/items/coin.png +0 -0
  29. package/assets/items/gem.png +0 -0
  30. package/assets/items/gold.png +0 -0
  31. package/assets/items/hp_potion.png +0 -0
  32. package/assets/items/locked_item_box.png +0 -0
  33. package/assets/items/map.png +0 -0
  34. package/assets/items/resurrection_potion.png +0 -0
  35. package/assets/items/super_box.png +0 -0
  36. package/assets/items/trap.png +0 -0
  37. package/assets/tiles/floor00.jpg +0 -0
  38. package/assets/tiles/minecraft-tiles.png +0 -0
  39. package/assets/tiles/wall00.jpg +0 -0
  40. package/assets/vegetation/ash_color.png +0 -0
  41. package/assets/vegetation/aspen_color.png +0 -0
  42. package/assets/vegetation/bark/birch_color_1k.jpg +0 -0
  43. package/assets/vegetation/bark/birch_normal_1k.jpg +0 -0
  44. package/assets/vegetation/bark/birch_roughness_1k.jpg +0 -0
  45. package/assets/vegetation/bark/oak_color_1k.jpg +0 -0
  46. package/assets/vegetation/bark/oak_normal_1k.jpg +0 -0
  47. package/assets/vegetation/bark/oak_roughness_1k.jpg +0 -0
  48. package/assets/vegetation/bark/pine_color_1k.jpg +0 -0
  49. package/assets/vegetation/bark/pine_normal_1k.jpg +0 -0
  50. package/assets/vegetation/bark/pine_roughness_1k.jpg +0 -0
  51. package/assets/vegetation/ground/dirt_color.jpg +0 -0
  52. package/assets/vegetation/ground/dirt_normal.jpg +0 -0
  53. package/assets/vegetation/ground/grass.jpg +0 -0
  54. package/assets/vegetation/oak_color.png +0 -0
  55. package/assets/vegetation/pine_color.png +0 -0
  56. package/bin/incanto-assets.mjs +107 -0
  57. package/bin/incanto-check.mjs +107 -0
  58. package/bin/incanto-editor.mjs +343 -0
  59. package/bin/incanto-env.mjs +144 -0
  60. package/bin/incanto-model.mjs +296 -0
  61. package/bin/incanto-play.mjs +219 -0
  62. package/bin/incanto-skills.mjs +71 -0
  63. package/dist/2d.d.ts +642 -0
  64. package/dist/2d.js +44 -0
  65. package/dist/3d.d.ts +1860 -0
  66. package/dist/3d.js +5 -0
  67. package/dist/agent8-DzU2fFyH.js +129 -0
  68. package/dist/audio-player-DqUR3XFs.d.ts +110 -0
  69. package/dist/behavior-BAQq7HGM.d.ts +851 -0
  70. package/dist/create-game-BdjpTHrW.js +1725 -0
  71. package/dist/create-game-CZHROKcT.js +527 -0
  72. package/dist/debug-draw-CZmOYjL2.js +13 -0
  73. package/dist/debug.d.ts +66 -0
  74. package/dist/debug.js +658 -0
  75. package/dist/duplicate-DP2WPYom.js +22 -0
  76. package/dist/env.d.ts +430 -0
  77. package/dist/env.js +3152 -0
  78. package/dist/errors-BMFaY68Q.d.ts +33 -0
  79. package/dist/errors-BpWbnbb_.js +13 -0
  80. package/dist/gameplay-Ccruc3Wd.js +1501 -0
  81. package/dist/gameplay.d.ts +543 -0
  82. package/dist/gameplay.js +2 -0
  83. package/dist/heightmap-CroQPEER.js +185 -0
  84. package/dist/index.d.ts +305 -0
  85. package/dist/index.js +62 -0
  86. package/dist/json-BLk7H2Qa.js +30 -0
  87. package/dist/loader-CGs_G-r0.js +919 -0
  88. package/dist/loader-Mo0KghCv.d.ts +41 -0
  89. package/dist/net.d.ts +427 -0
  90. package/dist/net.js +772 -0
  91. package/dist/noise-CGUMx44x.js +82 -0
  92. package/dist/particle-sim-CbN4YUuH.d.ts +63 -0
  93. package/dist/particle-sim-DYuSUxvK.js +1319 -0
  94. package/dist/physics-2d-KuMWPTf6.js +288 -0
  95. package/dist/physics-3d-Dl67vOLT.js +434 -0
  96. package/dist/react.d.ts +65 -0
  97. package/dist/react.js +209 -0
  98. package/dist/register-BuUV1_KB.js +561 -0
  99. package/dist/register-CNlYAS1_.js +10634 -0
  100. package/dist/register-DPEV9_9t.js +851 -0
  101. package/dist/register-Dasmnurl.js +374 -0
  102. package/dist/registry-BVJ2HbCn.js +132 -0
  103. package/dist/rng-DP-SR7eg.js +38 -0
  104. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  105. package/dist/schema-CcoWb32N.d.ts +104 -0
  106. package/dist/test.d.ts +158 -0
  107. package/dist/test.js +275 -0
  108. package/dist/touch-031PxtCR.js +208 -0
  109. package/dist/vite.d.ts +26 -0
  110. package/dist/vite.js +57 -0
  111. package/editor/assets/GameServer-C56iOUgF.js +1 -0
  112. package/editor/assets/agent8-Bp7QFI7v.js +1 -0
  113. package/editor/assets/index-DF3tMeKJ.css +1 -0
  114. package/editor/assets/index-Dl2pjA8e.js +7365 -0
  115. package/editor/assets/rapier-CEuLKeCu.js +1 -0
  116. package/editor/assets/rapier-DE6a0vmv.js +1 -0
  117. package/editor/index.html +169 -0
  118. package/package.json +97 -0
  119. package/schemas/scene.schema.json +4254 -0
  120. package/skills/README.md +9 -0
  121. package/skills/incanto-3d-character.md +229 -0
  122. package/skills/incanto-3d-models.md +151 -0
  123. package/skills/incanto-assets.md +118 -0
  124. package/skills/incanto-audio.md +309 -0
  125. package/skills/incanto-behaviors-and-scripts.md +169 -0
  126. package/skills/incanto-building-2d-games.md +242 -0
  127. package/skills/incanto-building-3d-games.md +245 -0
  128. package/skills/incanto-editor.md +163 -0
  129. package/skills/incanto-environment.md +743 -0
  130. package/skills/incanto-gameplay-behaviors.md +707 -0
  131. package/skills/incanto-multiplayer.md +264 -0
  132. package/skills/incanto-node-reference.md +797 -0
  133. package/skills/incanto-physics-and-input.md +164 -0
  134. package/skills/incanto-scene-json-authoring.md +325 -0
  135. package/skills/incanto-verifying-your-game.md +191 -0
  136. package/skills/incanto-web-integration.md +96 -0
  137. package/templates/agent8-server.js +84 -0
  138. package/templates/agent8-server.ts +138 -0
@@ -0,0 +1,543 @@
1
+ import { c as JsonValue } from "./schema-CcoWb32N.js";
2
+ import { T as Node, l as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-BAQq7HGM.js";
3
+
4
+ //#region src/gameplay/chase.d.ts
5
+ /**
6
+ * Home in on a target node — the workhorse enemy AI. Each frame moves toward
7
+ * `target.position` at `speed`, stopping once within `stopRange` (melee reach).
8
+ * Dimension-agnostic.
9
+ *
10
+ * - `reachedTarget` fires once when it first enters `stopRange` (re-arms after
11
+ * it leaves), so wire it to an attack.
12
+ * - `loseRange` (>0) gives up the chase when the target gets that far away,
13
+ * emitting `lostTarget` once.
14
+ * - `moveParent` (default false) moves the parent node instead of this one.
15
+ * A node carries ONE behavior, so an enemy whose ROOT must hold `Health`
16
+ * (e.g. for `Health.freeOnDeath` clone-safe cleanup) puts `Chase` on a CHILD
17
+ * and sets `moveParent:true` — the AI child drives the whole entity. Distance
18
+ * is measured from the moved node (the parent).
19
+ */
20
+ declare class Chase extends Behavior {
21
+ static readonly props: PropSchema;
22
+ static readonly signals: readonly string[];
23
+ target: string;
24
+ speed: number;
25
+ stopRange: number;
26
+ loseRange: number;
27
+ moveParent: boolean;
28
+ private inRange;
29
+ private lost;
30
+ override onReady(): void;
31
+ override update(dt: number): void;
32
+ }
33
+ //#endregion
34
+ //#region src/gameplay/collector.d.ts
35
+ /**
36
+ * A tally for the "collect N things" pattern, living on the collector itself
37
+ * (usually the player). Adds its node to `group` at ready so Pickups whose
38
+ * `collectorGroup` matches will count it as a collector.
39
+ *
40
+ * Wire a Pickup's `collected(value, other) → Collector.collect` (the value is
41
+ * the first arg) — `total` accumulates and `totalChanged(total)` fires.
42
+ * (Pickup also notifies a global ScoreKeeper; Collector is the per-actor tally,
43
+ * e.g. for split-screen or "each player's coins".)
44
+ */
45
+ declare class Collector extends Behavior {
46
+ static readonly props: PropSchema;
47
+ static readonly signals: readonly string[];
48
+ group: string;
49
+ /** Running sum of collected values. */
50
+ total: number;
51
+ override onReady(): void;
52
+ /** Add `value` to the tally and emit `totalChanged`. */
53
+ collect(value: number): void;
54
+ }
55
+ //#endregion
56
+ //#region src/gameplay/health.d.ts
57
+ /**
58
+ * Hit points with regeneration and post-hit invulnerability (i-frames) —
59
+ * the universal "this thing can be hurt and can die" behavior.
60
+ *
61
+ * Other behaviors hurt it through `damage(n)` (e.g. `DamageOnContact` finds a
62
+ * target's Health and calls it); games heal/kill via `heal(n)` / `kill()`.
63
+ * Wire its `died` signal to a `ScoreKeeper.loseLife`, a respawn, etc.
64
+ *
65
+ * `freeOnDeath` (default false) `queueFree()`s the Health node itself when it
66
+ * dies. Because it is NODE-LOCAL it clones perfectly — this is THE way to free
67
+ * dying SPAWNED entities. Scene-level `connections` (e.g. `died → queueFree`)
68
+ * are NOT copied onto Spawner/WaveSpawner clones, so a `died` connection only
69
+ * ever wires the template, never the live clones; `freeOnDeath` needs no
70
+ * connection and so works on every clone.
71
+ *
72
+ * Dimension-agnostic: no node geometry, just numbers — testable headlessly.
73
+ */
74
+ declare class Health extends Behavior {
75
+ static readonly props: PropSchema;
76
+ static readonly signals: readonly string[];
77
+ max: number;
78
+ regenPerSec: number;
79
+ invulnerableFor: number;
80
+ freeOnDeath: boolean;
81
+ /** Current hit points (set to `max` on ready). */
82
+ current: number;
83
+ private invulnTimer;
84
+ private dead;
85
+ /** True once `current` has hit 0 — `died` fires at most once per life. */
86
+ get isDead(): boolean;
87
+ /** Seconds of i-frames remaining (0 = vulnerable). */
88
+ get invulnerableRemaining(): number;
89
+ override onReady(): void;
90
+ override update(dt: number): void;
91
+ /** Apply `n` damage. No-op while invulnerable or already dead. Emits `damaged`. */
92
+ damage(n: number): void;
93
+ /** Restore `n` hit points (clamped to `max`). No-op when dead. Emits `healed`. */
94
+ heal(n: number): void;
95
+ /** Drop to 0 and die immediately (ignores i-frames). */
96
+ kill(): void;
97
+ private setCurrent;
98
+ private die;
99
+ }
100
+ //#endregion
101
+ //#region src/gameplay/damage-on-contact.d.ts
102
+ /**
103
+ * Deals damage to whatever it touches — projectiles, spikes, lava, enemy
104
+ * hitboxes. Must sit on an Area2D/Area3D (listens to `triggerEnter`).
105
+ *
106
+ * On overlap it finds the contacted entity's `Health` behavior (see
107
+ * `findHealth` for the exact search order) and calls `damage(amount)`, then
108
+ * emits `dealtDamage(amount, targetNode)`.
109
+ *
110
+ * - `targetGroup` (default '' = anything) gates who can be hurt: only a target
111
+ * whose Health-owner node is in that group takes damage. This is how you stop
112
+ * enemies killing each other — give the player's weapon `targetGroup:'enemy'`
113
+ * and each enemy's contact hitbox `targetGroup:'player'`.
114
+ * - `oncePerTarget` (default) prevents re-hitting the same node (a stationary
115
+ * hazard would otherwise drain a resting body every frame).
116
+ * - `destroySelf` frees the hazard after a hit (single-use projectiles).
117
+ *
118
+ * SCORING PATTERN (clone-safe): wire the KILLER's `dealtDamage` →
119
+ * `ScoreKeeper.addScore`. The weapon is usually a non-cloned node (it lives on
120
+ * the player), so a scene connection on it survives — unlike a connection on a
121
+ * spawned enemy, which never clones.
122
+ */
123
+ declare class DamageOnContact extends Behavior {
124
+ static readonly props: PropSchema;
125
+ static readonly signals: readonly string[];
126
+ amount: number;
127
+ targetGroup: string;
128
+ oncePerTarget: boolean;
129
+ destroySelf: boolean;
130
+ private readonly hit;
131
+ override onReady(): void;
132
+ private tryDamage;
133
+ }
134
+ //#endregion
135
+ //#region src/gameplay/follow-camera.d.ts
136
+ /**
137
+ * Make the node it sits on chase a target's position — THE camera-follow
138
+ * behavior. Put it on a `Camera2D`/`Camera3D` (whose `position` is the view
139
+ * center/eye) and point `target` at the player; every frame the camera lerps
140
+ * toward `target.position + offset`.
141
+ *
142
+ * Dimension-agnostic: works on `[x,y]` (2D) and `[x,y,z]` (3D) positions.
143
+ *
144
+ * - `smoothing` (0..1) is a per-frame retention factor: 0 = instant snap,
145
+ * 0.85–0.95 = smooth drag (frame-rate independent at a 60fps reference).
146
+ * - `deadzone` keeps the camera still until the target drifts that far from the
147
+ * desired point — no jitter when the player makes tiny moves.
148
+ */
149
+ declare class FollowCamera extends Behavior {
150
+ static readonly props: PropSchema;
151
+ static readonly signals: readonly string[];
152
+ target: string;
153
+ offset: number[];
154
+ smoothing: number;
155
+ deadzone: number;
156
+ override onReady(): void;
157
+ override update(dt: number): void;
158
+ }
159
+ //#endregion
160
+ //#region src/gameplay/interactable.d.ts
161
+ /**
162
+ * A proximity-gated "press to use" — doors, levers, chests, NPCs. Each frame,
163
+ * if an actor in `actorGroup` is within `range` (distance on `position` arrays,
164
+ * 2D or 3D) and the `action` input was just pressed, emits
165
+ * `interacted(actor)` (the nearest in-range actor).
166
+ *
167
+ * Wire `interacted → YourBehavior.someMethod`, or read it from a connection.
168
+ */
169
+ declare class Interactable extends Behavior {
170
+ static readonly props: PropSchema;
171
+ static readonly signals: readonly string[];
172
+ action: string;
173
+ range: number;
174
+ actorGroup: string;
175
+ override update(): void;
176
+ }
177
+ //#endregion
178
+ //#region src/gameplay/lifetime.d.ts
179
+ /**
180
+ * Self-destruct after a fixed time — bullets, particles, temporary spawns,
181
+ * pickups that vanish. Accumulates `dt`; on elapse emits `expired` then
182
+ * `queueFree()`s its node.
183
+ *
184
+ * With `startOnSignal: true` the countdown is armed manually via `startTimer()`
185
+ * (wire a signal → `startTimer`), so the lifetime begins on an event rather
186
+ * than at spawn.
187
+ */
188
+ declare class Lifetime extends Behavior {
189
+ static readonly props: PropSchema;
190
+ static readonly signals: readonly string[];
191
+ seconds: number;
192
+ startOnSignal: boolean;
193
+ private elapsed;
194
+ private running;
195
+ private fired;
196
+ override onReady(): void;
197
+ /** Arm (or re-arm) the countdown from zero. */
198
+ startTimer(): void;
199
+ override update(dt: number): void;
200
+ }
201
+ //#endregion
202
+ //#region src/gameplay/tween.d.ts
203
+ /** Easing curves shared by the tween behaviors (MoveTo, …). Pure math. */
204
+ type EaseName = "linear" | "easeIn" | "easeOut" | "easeInOut";
205
+ //#endregion
206
+ //#region src/gameplay/move-to.d.ts
207
+ /**
208
+ * Tween the node from where it starts to a fixed `to` position over `duration`
209
+ * seconds, through an easing curve — opening doors, sliding platforms, UI
210
+ * pop-ins, scripted moves. Emits `arrived` once at the end.
211
+ *
212
+ * `startOnSignal: true` arms it manually via `start()` (wire a signal → `start`)
213
+ * so the move plays on an event; otherwise it begins at ready. Dimension-
214
+ * agnostic (`[x,y]` / `[x,y,z]`).
215
+ */
216
+ declare class MoveTo extends Behavior {
217
+ static readonly props: PropSchema;
218
+ static readonly signals: readonly string[];
219
+ to: number[];
220
+ duration: number;
221
+ ease: EaseName;
222
+ startOnSignal: boolean;
223
+ private from;
224
+ private elapsed;
225
+ private running;
226
+ private arrivedFired;
227
+ override onReady(): void;
228
+ /** Begin (or restart) the move from the node's CURRENT position. */
229
+ start(): void;
230
+ override update(dt: number): void;
231
+ }
232
+ //#endregion
233
+ //#region src/gameplay/oscillate.d.ts
234
+ declare const AXES: readonly ["x", "y", "z"];
235
+ type Axis = (typeof AXES)[number];
236
+ declare const MODES: readonly ["position", "rotation", "scale"];
237
+ type Mode = (typeof MODES)[number];
238
+ /**
239
+ * Continuous sine motion around a value — floating platforms, bobbing pickups,
240
+ * spinning/pulsing coins. Drives one `axis` of the node's `position`, `rotation`
241
+ * (`mode: 'rotation'` — a "spin" when on z), or `scale` (a "pulse"):
242
+ *
243
+ * value = start + amplitude · sin(2π · frequency · t)
244
+ *
245
+ * The baseline (`start`) is captured at ready, so it layers on top of authored
246
+ * transforms. Dimension-agnostic; on a 2D node `rotation` is the scalar spin
247
+ * (use `axis: 'z'`).
248
+ */
249
+ declare class Oscillate extends Behavior {
250
+ static readonly props: PropSchema;
251
+ static readonly signals: readonly string[];
252
+ axis: Axis;
253
+ amplitude: number;
254
+ frequency: number;
255
+ mode: Mode;
256
+ private base;
257
+ private time;
258
+ override onReady(): void;
259
+ override update(dt: number): void;
260
+ /** Whether the target channel is the node's scalar 2D rotation. */
261
+ private isScalarRotation;
262
+ private readChannel;
263
+ private writeChannel;
264
+ }
265
+ //#endregion
266
+ //#region src/gameplay/patrol.d.ts
267
+ /**
268
+ * Walk the node along a fixed list of waypoints at constant speed — guards,
269
+ * platforms, moving hazards. `points` are positions (`[x,y]` / `[x,y,z]`) OR
270
+ * node paths whose `position` is read each frame (so you can author markers in
271
+ * the scene). On arrival emits `reachedPoint(index)`; `pauseAt` holds at each
272
+ * point before moving on.
273
+ *
274
+ * - `loop` (default) — after the last point, head back to the first.
275
+ * - `mode: 'pingpong'` — reverse direction at each end instead of wrapping.
276
+ */
277
+ declare class Patrol extends Behavior {
278
+ static readonly props: PropSchema;
279
+ static readonly signals: readonly string[];
280
+ points: JsonValue[];
281
+ speed: number;
282
+ loop: boolean;
283
+ mode: string;
284
+ pauseAt: number;
285
+ private index;
286
+ private direction;
287
+ private pauseTimer;
288
+ override onReady(): void;
289
+ override update(dt: number): void;
290
+ /** Resolve waypoint `i` to a position, reading node paths live. */
291
+ private pointAt;
292
+ private advance;
293
+ }
294
+ //#endregion
295
+ //#region src/gameplay/pickup.d.ts
296
+ /**
297
+ * A collectible that vanishes when a collector overlaps it. Must sit on an
298
+ * Area2D/Area3D (it listens to the unified `triggerEnter`).
299
+ *
300
+ * On overlap with a node in `collectorGroup`, emits `collected(value, other)`
301
+ * then `queueFree()`s itself. Wire `collected → ScoreKeeper.addScore` (the
302
+ * value is the first arg) or `collected → Collector.collect`.
303
+ */
304
+ declare class Pickup extends Behavior {
305
+ static readonly props: PropSchema;
306
+ static readonly signals: readonly string[];
307
+ value: number;
308
+ kind: string;
309
+ collectorGroup: string;
310
+ private collectedAlready;
311
+ override onReady(): void;
312
+ private tryCollect;
313
+ }
314
+ //#endregion
315
+ //#region src/gameplay/projectile.d.ts
316
+ /**
317
+ * Constant-velocity motion in a straight line — bullets, arrows, thrown rocks.
318
+ * Pure movement by design: pair it with `DamageOnContact` (deal damage on hit),
319
+ * `Lifetime` (auto-despawn), and an Area collider on the same node. Compose,
320
+ * don't conflate.
321
+ *
322
+ * `direction` is either an explicit vector (`[x,y]` / `[x,y,z]`, normalized) or
323
+ * the string `'forward'`, derived from the node's `rotation` (2D: degrees
324
+ * clockwise, +x at 0). It is a union-typed prop, so its schema default is
325
+ * `null` (the engine's "any JSON" escape hatch) and `null` means `'forward'`.
326
+ * `gravity` adds a constant downward (+y, the 2D y-down convention) pull, for
327
+ * lobbed/arcing shots.
328
+ */
329
+ declare class Projectile extends Behavior {
330
+ static readonly props: PropSchema;
331
+ static readonly signals: readonly string[];
332
+ speed: number;
333
+ direction: JsonValue;
334
+ gravity: number;
335
+ private velocity;
336
+ override onReady(): void;
337
+ override update(dt: number): void;
338
+ /** Resolve `direction` to a unit vector, deriving 'forward' from rotation. */
339
+ private resolveDirection;
340
+ private forwardFromRotation;
341
+ }
342
+ //#endregion
343
+ //#region src/gameplay/score-keeper.d.ts
344
+ /**
345
+ * The game's state hub — score, lives, and win/lose detection. Put it on the
346
+ * Root/Game node and wire gameplay signals into its methods (e.g. a Pickup's
347
+ * `collected → addScore`, a Health's `died → loseLife`).
348
+ *
349
+ * - `score` rises via `addScore` / `setScore`; reaching `scoreToWin` (>0)
350
+ * emits `won` once.
351
+ * - `lives` (>0) shrinks via `loseLife`; reaching 0 emits `lost` once.
352
+ */
353
+ declare class ScoreKeeper extends Behavior {
354
+ static readonly props: PropSchema;
355
+ static readonly signals: readonly string[];
356
+ score: number;
357
+ lives: number;
358
+ scoreToWin: number;
359
+ private hasWon;
360
+ private hasLost;
361
+ override onReady(): void;
362
+ /** Add `n` to the score (negative subtracts), emit `scoreChanged`, check win. */
363
+ addScore(n: number): void;
364
+ /** Set the score to `value`, emit `scoreChanged`, check win. */
365
+ setScore(value: number): void;
366
+ /** Lose one life (no-op when lives disabled or already lost). Emits `lifeLost`, then `lost` at 0. */
367
+ loseLife(): void;
368
+ }
369
+ //#endregion
370
+ //#region src/gameplay/spawner.d.ts
371
+ /**
372
+ * Drip-feed clones of a template into the scene on a timer — enemy generators,
373
+ * pickup fountains, particle emitters. `prefab` is a node PATH to a template
374
+ * (usually a hidden `visible: false` child) that gets cloned each `interval`.
375
+ *
376
+ * - `max` caps LIVE instances (0 = unlimited); the count drops automatically as
377
+ * spawned children free themselves (e.g. via `Lifetime` or `Health.died`), so
378
+ * the spawner refills.
379
+ * - `total` caps LIFETIME spawns (0 = infinite); on the last one it emits
380
+ * `finished` and stops.
381
+ * - `autoStart` (default) begins ticking at ready; otherwise call `start()`.
382
+ *
383
+ * Emits `spawned(node)` per spawn. Methods: `spawn()`, `start()`, `stop()`.
384
+ */
385
+ declare class Spawner extends Behavior {
386
+ static readonly props: PropSchema;
387
+ static readonly signals: readonly string[];
388
+ prefab: string;
389
+ interval: number;
390
+ max: number;
391
+ at: number[];
392
+ autoStart: boolean;
393
+ total: number;
394
+ private readonly source;
395
+ private template;
396
+ private readonly live;
397
+ private timer;
398
+ private running;
399
+ private spawnedCount;
400
+ private done;
401
+ /** Live (un-freed) spawned instances. */
402
+ get liveCount(): number;
403
+ /** @internal The detached template node (test/debug only). */
404
+ _templateForTest(): Node;
405
+ override onReady(): void;
406
+ /** Begin (or resume) interval spawning. */
407
+ start(): void;
408
+ /** Pause interval spawning (spawn() still works). */
409
+ stop(): void;
410
+ /** Spawn one immediately (ignores the timer; still respects max/total). */
411
+ spawn(): Node | null;
412
+ override update(dt: number): void;
413
+ /** Drop instances that have been freed (parent cleared on free/queueFree). */
414
+ private prune;
415
+ }
416
+ //#endregion
417
+ //#region src/gameplay/wander.d.ts
418
+ /**
419
+ * Aimless roaming inside a circle around the spawn point — idle critters,
420
+ * ambient wildlife, restless guards. Picks a random destination within `radius`
421
+ * of where it started, walks there at `speed`, then (every `changeEvery`
422
+ * seconds, or on arrival) picks a new one. Uses `this.rng`, so a seeded engine
423
+ * wanders identically every run (replayable, test-stable).
424
+ *
425
+ * Dimension-agnostic: roams in the plane of however many position components
426
+ * the node has (2D `[x,y]`, 3D `[x,z]` ground plane keeping y).
427
+ */
428
+ declare class Wander extends Behavior {
429
+ static readonly props: PropSchema;
430
+ static readonly signals: readonly string[];
431
+ speed: number;
432
+ radius: number;
433
+ changeEvery: number;
434
+ private origin;
435
+ private goal;
436
+ private timer;
437
+ override onReady(): void;
438
+ override update(dt: number): void;
439
+ private pickGoal;
440
+ }
441
+ //#endregion
442
+ //#region src/gameplay/wave-spawner.d.ts
443
+ /**
444
+ * Sequenced enemy waves — the survivor/tower-defense backbone. Each entry in
445
+ * `waves` is `{ prefab, count, interval, delayBefore }`: after `delayBefore`
446
+ * seconds it spawns `count` clones of `prefab` (a hidden template path) one
447
+ * every `interval` seconds, then waits until they're ALL cleared (freed) before
448
+ * starting the next wave.
449
+ *
450
+ * Signals: `waveStarted(i)` when a wave begins spawning, `waveCleared(i)` when
451
+ * its last instance frees, `allCleared` after the final wave clears.
452
+ */
453
+ declare class WaveSpawner extends Behavior {
454
+ static readonly props: PropSchema;
455
+ static readonly signals: readonly string[];
456
+ waves: JsonValue[];
457
+ autoStart: boolean;
458
+ private readonly source;
459
+ private parsed;
460
+ private readonly live;
461
+ private waveIndex;
462
+ private phase;
463
+ private timer;
464
+ private spawnedThisWave;
465
+ private announced;
466
+ override onReady(): void;
467
+ /** Start (or restart from) wave 0. */
468
+ start(): void;
469
+ override update(dt: number): void;
470
+ private beginWave;
471
+ private prune;
472
+ private parseWave;
473
+ }
474
+ //#endregion
475
+ //#region src/gameplay/zombie-ai.d.ts
476
+ /**
477
+ * The staple "zombie / monster" AI: SHAMBLE around on its own, then LOCK ON and
478
+ * CHARGE a target (the player) once it wanders within `aggroRange` — giving up
479
+ * again past `deAggroRange` (hysteresis, so it doesn't flicker at the boundary).
480
+ * One behavior covers both phases so a single node can be a complete enemy
481
+ * (`Wander` + `Chase` can't co-exist — a node carries ONE behavior).
482
+ *
483
+ * While NOT aggroed it roams: with `goalTarget` set it DRIFTS toward that node
484
+ * (e.g. the objective the horde is marching on) with random lateral jitter, so it
485
+ * reads as wandering yet still advances; without one it roams around its spawn.
486
+ *
487
+ * Emits `movementStateChanged('idle'|'walk'|'run')` on every change so a skin can
488
+ * swap animation clips (shamble while roaming, sprint while charging), plus
489
+ * `enteredAggro` / `exitedAggro` (wire to a growl, a glow, a speed-up).
490
+ *
491
+ * Dimension-agnostic; in 3D it moves only in the ground plane (x,z) and leaves
492
+ * the up axis (y) to physics, so a CharacterBody3D settles on terrain.
493
+ *
494
+ * `moveParent` (default false) moves the parent instead of this node — the
495
+ * AI-on-a-child pattern, so the entity ROOT can hold `Health` (clone-safe
496
+ * `freeOnDeath`) while this child drives movement.
497
+ */
498
+ declare class ZombieAI extends Behavior {
499
+ static readonly props: PropSchema;
500
+ static readonly signals: readonly string[];
501
+ aggroTarget: string;
502
+ aggroRange: number;
503
+ deAggroRange: number;
504
+ chaseSpeed: number;
505
+ wanderSpeed: number;
506
+ wanderRadius: number;
507
+ wanderChangeEvery: number;
508
+ goalTarget: string;
509
+ stopRange: number;
510
+ moveParent: boolean;
511
+ private aggro;
512
+ private started;
513
+ private home;
514
+ private goal;
515
+ private timer;
516
+ private lastState;
517
+ /** The node we actually move (the parent under moveParent, else this one). */
518
+ private mover;
519
+ private effectiveDeAggro;
520
+ override onReady(): void;
521
+ override update(dt: number): void;
522
+ /** Move `mover` toward `to` in the GROUND PLANE; returns true once within
523
+ * stopRange (no overshoot). Leaves the up axis (3D y) to physics. */
524
+ private approach;
525
+ /** Distance ignoring the up axis in 3D (so terrain height never blocks aggro). */
526
+ private groundDistance;
527
+ private setState;
528
+ private pickGoal;
529
+ }
530
+ //#endregion
531
+ //#region src/gameplay/index.d.ts
532
+ /** Every built-in gameplay behavior, keyed by its registration name. */
533
+ declare const GAMEPLAY_BEHAVIORS: Readonly<Record<string, BehaviorCtor>>;
534
+ /**
535
+ * Register all built-in gameplay behaviors. Idempotent and hot-reload tolerant
536
+ * (`replace: true`) — calling it twice, or after a user already registered a
537
+ * same-named behavior, is safe; pass `replace: false` to fail on conflicts.
538
+ */
539
+ declare function registerGameplayBehaviors(opts?: {
540
+ replace?: boolean;
541
+ }): void;
542
+ //#endregion
543
+ export { Chase, Collector, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, registerGameplayBehaviors };
@@ -0,0 +1,2 @@
1
+ import { _ as Health, a as Wander, c as Projectile, d as Oscillate, f as MoveTo, g as DamageOnContact, h as FollowCamera, i as WaveSpawner, l as Pickup, m as Interactable, n as registerGameplayBehaviors, o as Spawner, p as Lifetime, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as Collector, y as Chase } from "./gameplay-Ccruc3Wd.js";
2
+ export { Chase, Collector, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, registerGameplayBehaviors };