incanto 0.65.0 → 0.67.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 (88) hide show
  1. package/bin/_behaviors-loader.mjs +87 -0
  2. package/bin/incanto-editor.mjs +39 -2
  3. package/bin/incanto-feel.mjs +4 -1
  4. package/bin/incanto-frame.mjs +52 -3
  5. package/bin/incanto-logs.mjs +33 -3
  6. package/bin/incanto-multiplay.mjs +50 -1
  7. package/bin/incanto-play.mjs +3 -1
  8. package/bin/incanto-playtest.mjs +3 -25
  9. package/bin/incanto-verify.mjs +15 -2
  10. package/dist/2d.d.ts +76 -4
  11. package/dist/2d.js +3 -3
  12. package/dist/3d.d.ts +213 -14
  13. package/dist/3d.js +6 -6
  14. package/dist/{audio-player-BrEHwbK1.d.ts → audio-player-BNUHo0JF.d.ts} +1 -1
  15. package/dist/{behavior-CmMuQ6CL.d.ts → behavior-ZnfzKDo3.d.ts} +58 -1
  16. package/dist/{create-game-DIyh5Zy9.js → create-game-DMetd3vR.js} +14 -8
  17. package/dist/{create-game-W2xzTJhs.js → create-game-FAXdHta3.js} +138 -11
  18. package/dist/debug.d.ts +1 -1
  19. package/dist/debug.js +3 -2
  20. package/dist/{duplicate-CqSAtdrh.js → duplicate-B8QnX2-r.js} +1 -1
  21. package/dist/editor.js +7 -2
  22. package/dist/{environment-presets-BvHs6HEk.js → environment-presets-C-5g2pMh.js} +113 -9
  23. package/dist/{gameplay-D-H986A4.js → gameplay-CGSv-9XR.js} +295 -12
  24. package/dist/gameplay.d.ts +102 -6
  25. package/dist/gameplay.js +2 -2
  26. package/dist/index.d.ts +50 -6
  27. package/dist/index.js +7 -6
  28. package/dist/{loader-CTB441z4.d.ts → loader-DyT30ArB.d.ts} +1 -1
  29. package/dist/{loader-lQDCwNag.js → loader-KZESOZmE.js} +148 -1
  30. package/dist/net.d.ts +2 -2
  31. package/dist/net.js +1 -1
  32. package/dist/{physics-2d-CmnunaR2.js → physics-2d-_B6zj3zU.js} +57 -4
  33. package/dist/{physics-3d-DULB1lD1.js → physics-3d-i1IeAY0F.js} +74 -5
  34. package/dist/{quiet-rapier-BAJ4K94N.js → quiet-rapier-C6fW4zcW.js} +14 -1
  35. package/dist/react.d.ts +1 -1
  36. package/dist/react.js +1 -1
  37. package/dist/{register-CgeR4ckF.js → register-Cs53CY7s.js} +110 -16
  38. package/dist/{register-DO5_Qp0Q.js → register-vIxU3Xbv.js} +38 -4
  39. package/dist/rendering-options-ByAdi8PF.js +184 -0
  40. package/dist/{replay-CEw2xAhG.js → replay-BkpDV51O.js} +4 -3
  41. package/dist/{replay-CThvwkcQ.d.ts → replay-D0GcEHYU.d.ts} +1 -1
  42. package/dist/{split-screen-DxZzC1nm.d.ts → split-screen-DD5eYIgW.d.ts} +2 -2
  43. package/dist/{split-screen-gb0c3xdb.js → split-screen-DS8RaUV_.js} +2 -2
  44. package/dist/{src-DYffzHbd.js → src-BLlsGJW9.js} +1 -1
  45. package/dist/{teardown-BordHL9o.js → teardown-LB9cTnXJ.js} +2 -2
  46. package/dist/{test-CXZuXs8k.js → test-81uZ967a.js} +127 -24
  47. package/dist/test.d.ts +7 -5
  48. package/dist/test.js +2 -2
  49. package/dist/{touch-DESwnpOc.js → touch-DEAmqGdf.js} +30 -186
  50. package/dist/vite.d.ts +0 -7
  51. package/dist/vite.js +13 -3
  52. package/editor/assets/{agent8-DO5qzIOD.js → agent8-C2jtNKbx.js} +1 -1
  53. package/editor/assets/debug-DoU3KeqS.js +3 -0
  54. package/editor/assets/{index-CqEUVaPN.js → index-CNqHojcC.js} +92 -92
  55. package/editor/index.html +1 -1
  56. package/package.json +1 -1
  57. package/schemas/scene.schema.json +20 -1
  58. package/skills/incanto-building-3d-games.md +19 -0
  59. package/skills/incanto-editor.md +5 -1
  60. package/skills/incanto-environment.md +2 -2
  61. package/skills/incanto-gameplay-behaviors.md +86 -7
  62. package/skills/incanto-hud.md +14 -1
  63. package/skills/incanto-multiplayer.md +14 -0
  64. package/skills/incanto-node-reference.md +60 -2
  65. package/skills/incanto-performance.md +35 -0
  66. package/skills/incanto-physics-and-input.md +69 -0
  67. package/skills/incanto-playtesting.md +15 -1
  68. package/skills/incanto-save-slots.md +21 -1
  69. package/skills/incanto-verifying-your-game.md +19 -0
  70. package/skills/incanto-web-integration.md +24 -3
  71. package/skills/incanto-your-first-game.md +4 -4
  72. package/templates-app/beacon-isle-3d/package.json +1 -1
  73. package/templates-app/beacon-isle-3d/src/game.scene.json +38 -19
  74. package/templates-app/platformer-2d/package.json +1 -1
  75. package/templates-app/platformer-2d/src/game.scene.json +99 -53
  76. package/templates-app/star-survivor/package.json +1 -1
  77. package/templates-app/star-survivor/src/game.scene.json +31 -17
  78. package/templates-app/tps-3d/package.json +1 -1
  79. package/templates-app/tps-3d/src/game.scene.json +14 -8
  80. package/templates-app/village-quest-3d/package.json +1 -1
  81. package/templates-app/village-quest-3d/src/grove.scene.json +20 -11
  82. package/templates-app/village-quest-3d/src/village.scene.json +10 -7
  83. package/editor/assets/debug-DntG9CVD.js +0 -3
  84. package/templates-app/beacon-isle-3d/coverage.json +0 -9
  85. package/templates-app/platformer-2d/coverage.json +0 -5
  86. package/templates-app/star-survivor/coverage.json +0 -5
  87. package/templates-app/tps-3d/coverage.json +0 -5
  88. package/templates-app/village-quest-3d/coverage.json +0 -9
@@ -293,6 +293,75 @@ Types — 2D: `fixed` (weld) · `revolute` (pin/hinge) · `rope` (max distance)
293
293
  distance at creation. `anchor`/`targetAnchor` are local offsets (px / m).
294
294
  Chains work (pendulums, bridges: each link a body + joint to the previous).
295
295
 
296
+ ## Pushing a body around (the API that was in no skill)
297
+
298
+ A dynamic `RigidBody2D`/`RigidBody3D` has a force API and none of these appeared
299
+ in any shipped skill, so an agent building a physics puzzle reported the engine
300
+ as having "no force/impulse API at all" and designed around its absence:
301
+
302
+ ```ts
303
+ const body = this.getNode('/root/Crate') as RigidBody3D;
304
+ body.applyImpulse([0, 6, 0]); // an instant kick, in mass*units/second
305
+ body.velocity = [2, 0, 0]; // or set the velocity outright
306
+ ```
307
+
308
+ `applyImpulse` is what the character controller itself runs on. It is an
309
+ IMPULSE, not a force: it changes velocity once, so a continuous push is one call
310
+ per frame from `update(dt)` scaled by `dt`.
311
+
312
+ Readable/writable body state: `velocity`, `mass`, `gravityScale`, `friction`,
313
+ `restitution`, `fixedRotation`. There is no torque call and no `angularVelocity`
314
+ yet — a body's spin can be neither set nor read.
315
+
316
+ ## What is inside this Area right now?
317
+
318
+ `triggerEnter(other)` / `triggerExit(other)` tell you about CROSSINGS. A pressure
319
+ plate, a capture point, "how many enemies are in the blast" and a shop trigger
320
+ all want OCCUPANCY, and asking used to mean keeping your own `Set` fed by those
321
+ two signals — plus a geometric re-check every frame, because a body that is
322
+ teleported or freed inside a sensor does not reliably announce its exit.
323
+
324
+ ```ts
325
+ const load = plate.overlapping('cargo')
326
+ .reduce((kg, b) => kg + ((b as RigidBody3D).mass ?? 0), 0);
327
+ door.open = load >= 60;
328
+ ```
329
+
330
+ `Area2D`/`Area3D` `overlapping(group?)` returns what the solver currently says is
331
+ inside, and drops freed nodes on read. **It includes the STATIC world** — a plate
332
+ laid into the floor genuinely contains the floor — so pass a group to ask the
333
+ question you usually mean.
334
+
335
+ ## Joints: the three things that decide whether yours works
336
+
337
+ 1. **There is no hinge in 3D.** The types are `fixed | spherical | rope | spring`.
338
+ A hinge is **two `spherical` joints at two points along the axis** — that
339
+ constrains rotation to the line between them, and it is exactly how a seesaw
340
+ or a door is built. (2D has `revolute` and needs none of this.)
341
+ 2. **`collide` decides whether the two ends touch, and its default reads the
342
+ type.** Rapier lets jointed bodies collide, and a hinge wants its bodies
343
+ overlapping at the pivot — so the contact solver fights the joint and flings
344
+ them. Before this, a first hinge produced a bar that spun chaotically forever
345
+ and threw a 40 kg box thirty metres, and the author nearly filed "spherical
346
+ joints inject energy".
347
+
348
+ | joint | default | why |
349
+ |---|---|---|
350
+ | `fixed` · `spherical` · `revolute` | **off** | a pivot's bodies overlap by construction |
351
+ | `rope` · `spring` | **on** | a tether anchors a thing to the world, and it still has to rest on it |
352
+
353
+ Set `true`/`false` to say it outright. **It governs the two JOINTED bodies
354
+ only** — never their contact with the rest of the world. Defaulting a spring
355
+ off drops a barrel roped to the floor straight through it, which is how this
356
+ table was arrived at.
357
+ 3. **`anchor`/`targetAnchor` are local offsets from each body's ORIGIN**,
358
+ resolved against the bodies' positions at load. If the two disagree the solver
359
+ snaps the body into place on the first frame, and a 4 cm typo is silent. Author
360
+ them with arithmetic (generate the scene) rather than by hand.
361
+
362
+ There are no joint limits or motors yet: bound a lever's travel with static
363
+ collision geometry in its way.
364
+
296
365
  ## Raycasts
297
366
 
298
367
  **Where `physics` comes from.** From a `Behavior` — where AI lives, and where
@@ -51,10 +51,24 @@ two.
51
51
  | `fell` | the player left the world past `--fall-below` (default: 50 m under the spawn in 3D, 1000 px under it in 2D) |
52
52
  | `error` | `stats().errors` went above zero — a behavior threw |
53
53
  | `stuck` | the clock ran out AND the player never got more than 3 m (96 px) from its spawn — it is wedged, or nothing moves it |
54
+ | `swapped` | the game changed scene. The bot binds player, destinations and the win/lose oracle ONCE, from the tree it started in, so nothing after a `goToScene` is measured — the run stops there and says so. It is not a defect, and the destinations it never got to are reported as unmeasured rather than missed. Judge a multi-scene game with a scripted `runScript`. |
54
55
  | `unfinished` | the clock ran out on a player that was getting around. Not a defect: a win that needs a SEQUENCE (talk to the NPC, then fetch, then return) is out of reach of a random walker, forever |
55
56
  | `never reached` | destinations the bot never came within `--reach-radius` of (default 2 m in 3D, 32 px in 2D) |
56
57
  | `never fired` | signals a `connections[]` entry listens to that never happened |
57
- | `danger` | how many times the player's `Health` emitted `damaged` |
58
+ | `danger` | how many times the player's `Health` emitted `damaged` — and when that is ZERO, WHICH zero it is: a scene with no hazard wired at all is a walkabout and worth shouting about; a scene full of them that never landed one is a report about the BOT, which a real player would outrun less easily. Hazards are counted from the scene FILE, because a `Spawner` detaches its prefab at ready and a wave game's hazards are not in the tree yet. |
59
+
60
+ **The bot can use the MOUSE.** If your scene has `Clickable` nodes, it presses
61
+ and releases over them at random — through the real `Clickable`, the real
62
+ `mouseJustPressed` edge and your real connection, with a picker that answers
63
+ from the tree (the recipe under "Testing a mouse-driven game headlessly"). It
64
+ drove actions and nothing else before, so a tactics game, a tower defense and a
65
+ duel all reported the identical `? plays — 8 runs played without reaching a
66
+ win`. A scene with nothing clickable is untouched: it does not gain an
67
+ `engine.picker` it never had.
68
+
69
+ A random clicker still cannot finish a game that needs a SEQUENCE — select a
70
+ trooper, then a tile, then end the turn — and that is reported as unmeasured,
71
+ not failed.
58
72
 
59
73
  **Nothing here is a guess about your design.** The scene already declares what
60
74
  winning is; this only listens.
@@ -89,7 +89,27 @@ game that shipped six weeks ago. Check what you read.
89
89
  Built-ins that already save: `Health` (current, dead), `ScoreKeeper` (score,
90
90
  lives, won/lost), `Collector` (total).
91
91
 
92
- ## Every node you save needs a uid
92
+ ## Every node you save — and every node that VANISHES — needs a uid
93
+
94
+ A collectible does not save state; it DISAPPEARS, and disappearing is the thing
95
+ the save has to record. `#freed` is keyed by uid, so a pickup without one is
96
+ silently omitted: the score that counted it restores, and the pickup restores
97
+ too. Measured on a starter with 1 uid across 141 nodes:
98
+
99
+ ```
100
+ coins after collecting : 9
101
+ save["#freed"] : undefined
102
+ restore report : { restored: 1, expected: 1, freed: 0 }
103
+ coins AFTER load : 12 <- three coins resurrected
104
+ auditScene warnings : [] <- and every checker was green
105
+ ```
106
+
107
+ `captureState` now reports this as an ERROR naming the nodes, because the save
108
+ it just wrote is already wrong. It does not guess a replacement: a uid survives
109
+ a rename and a reparent, and a saved PATH would point at whatever node moved
110
+ into that slot after your next edit.
111
+
112
+
93
113
 
94
114
  The uid is the join key, because it is the one identifier that survives a rename
95
115
  or a reparent. The editor assigns one to every node it touches. A hand-written
@@ -858,3 +858,22 @@ const inputToWorld = Math.atan2(at()[1] - before[1], at()[0] - before[0]);
858
858
 
859
859
  `examples/village-quest-3d/verify.ts` does exactly this and fails with
860
860
  "the player cannot reach it on foot" when it cannot.
861
+
862
+
863
+ ## When node refuses your TypeScript
864
+
865
+ The bins' shebang is node, and node's type stripping **erases** types — it does
866
+ not transform. Three ordinary things it refuses, all of which vite and bun
867
+ compile without comment:
868
+
869
+ | what you wrote | what node says |
870
+ |---|---|
871
+ | `import scene from './game.scene.json'` | needs an import attribute of "type: json" |
872
+ | `import { quest } from './quest'` | Cannot find module …/quest |
873
+ | `constructor(private root: Node3D)` | TypeScript parameter property is not supported in strip-only mode |
874
+
875
+ **You do not have to change any of them.** Every bin that loads a `--behaviors`
876
+ file re-runs itself under bun when node refuses it, so the command just works.
877
+ If bun is not on PATH the message says which of the three it hit.
878
+
879
+ Prefix with `bunx --bun` to skip the round trip.
@@ -58,9 +58,30 @@ export function GamePage() {
58
58
  Rule of thumb: score/menus/dialogs that look like WEB UI → DOM overlay;
59
59
  anything the game itself must own (and runScript must verify) → UILayer.
60
60
 
61
- Pin a DOM element to a world position: `game.renderer.screenFromWorld(wx, wy)`
62
- (and `worldFromScreen(sx, sy)` the other way, for taps and clicks)
63
- each frame (subscribe `engine.updated`), then `transform: translate(x, y)`.
61
+ Pin a DOM element to a world position each frame (subscribe `engine.updated`),
62
+ then `transform: translate(x, y)`:
63
+
64
+ ```ts
65
+ game.renderer.screenFromWorld(wx, wy) // 2D
66
+ game.renderer.screenFromWorld(wx, wy, wz) // 3D — takes THREE arguments
67
+ ```
68
+
69
+ Going the other way, for taps and clicks:
70
+
71
+ ```ts
72
+ game.renderer.worldFromScreen(sx, sy) // 2D → { x, y }
73
+ game.renderer.worldFromScreen(sx, sy, planeY?) // 3D → { x, y, z } on a
74
+ // horizontal plane (default y=0)
75
+ game.renderer.rayFromScreen(sx, sy) // 3D → { origin, dir } for
76
+ // physics.castRay on uneven ground
77
+ ```
78
+
79
+ **A pixel in 3D is a ray, not a point**, which is why the 3D form needs a
80
+ surface: `worldFromScreen` lands it on the ground plane, and `rayFromScreen`
81
+ hands you the ray when the ground is terrain or a stack of crates. Both return
82
+ null when the ray misses (looking at the sky). `pick(sx, sy)` gives you the NODE
83
+ under a pixel — a different question, and the only one 3D could answer before
84
+ 0.66.
64
85
 
65
86
  Perf note: `useNodeProp` deep-compares per frame — subscribe to LEAF values
66
87
  (`'UI/Score', 'text'`), not big objects like a whole `animations` map.
@@ -83,13 +83,13 @@ and it is entirely JSON.
83
83
  ```jsonc
84
84
  "connections": [
85
85
  { "signal": "died", "from": "Player", "to": "Score", "handler": "loseLife" },
86
- { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "revive" },
86
+ { "signal": "lifeLost", "from": "Score", "to": "Player", "handler": "reviveFull" },
87
87
  { "signal": "won", "from": "Score", "to": "Flow", "handler": "win" },
88
88
  { "signal": "lost", "from": "Score", "to": "Flow", "handler": "gameOver" }
89
89
  ]
90
90
  ```
91
91
 
92
- **`lifeLost → revive` is not optional.** A `Health` that has died stays dead:
92
+ **`lifeLost → reviveFull` is not optional.** A `Health` that has died stays dead:
93
93
  `damage`, `heal` and regen all stop, so without that wire the player becomes a
94
94
  walking corpse after the first death — full HP bar, immune to everything,
95
95
  `died` never firing again, lives frozen, and the game quietly unlosable. It
@@ -158,7 +158,7 @@ floats over small ledges already.
158
158
  The tell for both is one line of `incanto-playtest` output:
159
159
 
160
160
  ```
161
- danger: the player took damage 0 times in 4 runs — nothing here can hurt you
161
+ danger: nothing in this scene can hurt the player — no DamageOnContact, no hazard group
162
162
  ```
163
163
 
164
164
  Read it. It is the truth.
@@ -219,7 +219,7 @@ Things that cost real time, in the order you will meet them.
219
219
 
220
220
  | when | the trap |
221
221
  | --- | --- |
222
- | a game with LIVES | `died` stops a `Health` for good — wire `lifeLost → revive` or you can spend only one. |
222
+ | a game with LIVES | `died` stops a `Health` for good — wire `lifeLost → reviveFull` or you can spend only one. **Not `revive`**: `lifeLost` carries the life COUNT and `revive(hp?)` reads it as health, so you come back at 2 HP, then 1, then 0. |
223
223
  | wiring a score | `died` carries nothing; `addScore(n)` wants one → `NaN`. Wire `dealtDamage` from the killer. |
224
224
  | enemies feel harmless | `repeatEvery` on the contact hitbox, or one hit is all you get. |
225
225
  | enemies never arrive | a chaser cannot climb — `stepHeight`, and it loses to a large downward velocity you apply yourself. |
@@ -14,7 +14,7 @@
14
14
  "@dimforge/rapier2d-compat": "0.19.3",
15
15
  "@dimforge/rapier3d-compat": "0.19.3",
16
16
  "@pixiv/three-vrm": "^3.5.3",
17
- "incanto": "^0.65.0",
17
+ "incanto": "^0.67.0",
18
18
  "three": "^0.184.0"
19
19
  },
20
20
  "devDependencies": {
@@ -122,7 +122,8 @@
122
122
  "props": {
123
123
  "pausePanelPath": "%PauseMenu"
124
124
  }
125
- }
125
+ },
126
+ "uid": "n_59r4gykhbcuemdgu"
126
127
  },
127
128
  {
128
129
  "name": "Terrain",
@@ -1605,7 +1606,8 @@
1605
1606
  "volume": 0.5
1606
1607
  }
1607
1608
  }
1608
- ]
1609
+ ],
1610
+ "uid": "n_z47j96sgcxut952d"
1609
1611
  },
1610
1612
  {
1611
1613
  "name": "Ward1",
@@ -1973,7 +1975,8 @@
1973
1975
  "oncePerTarget": false,
1974
1976
  "repeatEvery": 1.2
1975
1977
  }
1976
- }
1978
+ },
1979
+ "uid": "n_z8vhukdcirpi88je"
1977
1980
  },
1978
1981
  {
1979
1982
  "name": "HissSfx",
@@ -1987,7 +1990,8 @@
1987
1990
  "maxDistance": 30
1988
1991
  }
1989
1992
  }
1990
- ]
1993
+ ],
1994
+ "uid": "n_n468rqi1ozzm61uu"
1991
1995
  },
1992
1996
  {
1993
1997
  "name": "Shade1_2",
@@ -2091,7 +2095,8 @@
2091
2095
  "oncePerTarget": false,
2092
2096
  "repeatEvery": 1.2
2093
2097
  }
2094
- }
2098
+ },
2099
+ "uid": "n_bq1hz55sxw1i1im1"
2095
2100
  },
2096
2101
  {
2097
2102
  "name": "HissSfx",
@@ -2105,7 +2110,8 @@
2105
2110
  "maxDistance": 30
2106
2111
  }
2107
2112
  }
2108
- ]
2113
+ ],
2114
+ "uid": "n_ny13372zziqzgpom"
2109
2115
  },
2110
2116
  {
2111
2117
  "name": "Shade2_1",
@@ -2209,7 +2215,8 @@
2209
2215
  "oncePerTarget": false,
2210
2216
  "repeatEvery": 1.2
2211
2217
  }
2212
- }
2218
+ },
2219
+ "uid": "n_y9jsyb615rpdggas"
2213
2220
  },
2214
2221
  {
2215
2222
  "name": "HissSfx",
@@ -2223,7 +2230,8 @@
2223
2230
  "maxDistance": 30
2224
2231
  }
2225
2232
  }
2226
- ]
2233
+ ],
2234
+ "uid": "n_r53mg0r2ctvvkvjj"
2227
2235
  },
2228
2236
  {
2229
2237
  "name": "Shade2_2",
@@ -2327,7 +2335,8 @@
2327
2335
  "oncePerTarget": false,
2328
2336
  "repeatEvery": 1.2
2329
2337
  }
2330
- }
2338
+ },
2339
+ "uid": "n_fg4pcm0kcpbzpqui"
2331
2340
  },
2332
2341
  {
2333
2342
  "name": "HissSfx",
@@ -2341,7 +2350,8 @@
2341
2350
  "maxDistance": 30
2342
2351
  }
2343
2352
  }
2344
- ]
2353
+ ],
2354
+ "uid": "n_y5kshgw9213y7eeo"
2345
2355
  },
2346
2356
  {
2347
2357
  "name": "Shade3_1",
@@ -2445,7 +2455,8 @@
2445
2455
  "oncePerTarget": false,
2446
2456
  "repeatEvery": 1.2
2447
2457
  }
2448
- }
2458
+ },
2459
+ "uid": "n_l9e6uonnlyg7m16w"
2449
2460
  },
2450
2461
  {
2451
2462
  "name": "HissSfx",
@@ -2459,7 +2470,8 @@
2459
2470
  "maxDistance": 30
2460
2471
  }
2461
2472
  }
2462
- ]
2473
+ ],
2474
+ "uid": "n_ojzy1ypkshyepyvy"
2463
2475
  },
2464
2476
  {
2465
2477
  "name": "Shade3_2",
@@ -2563,7 +2575,8 @@
2563
2575
  "oncePerTarget": false,
2564
2576
  "repeatEvery": 1.2
2565
2577
  }
2566
- }
2578
+ },
2579
+ "uid": "n_7xn82zimw6skfh3j"
2567
2580
  },
2568
2581
  {
2569
2582
  "name": "HissSfx",
@@ -2577,7 +2590,8 @@
2577
2590
  "maxDistance": 30
2578
2591
  }
2579
2592
  }
2580
- ]
2593
+ ],
2594
+ "uid": "n_l5g65a25w1r2yvby"
2581
2595
  },
2582
2596
  {
2583
2597
  "name": "Player",
@@ -2622,7 +2636,8 @@
2622
2636
  },
2623
2637
  "script": {
2624
2638
  "name": "SwordStrike"
2625
- }
2639
+ },
2640
+ "uid": "n_cyhj8t0qy5t3k94v"
2626
2641
  },
2627
2642
  {
2628
2643
  "name": "Skin",
@@ -2727,7 +2742,8 @@
2727
2742
  "nightDarkness": 0.32,
2728
2743
  "maxSunElevationDeg": 48
2729
2744
  }
2730
- }
2745
+ },
2746
+ "uid": "n_v447j9q4dnw2gwtj"
2731
2747
  },
2732
2748
  {
2733
2749
  "name": "Boss",
@@ -2878,7 +2894,8 @@
2878
2894
  "oncePerTarget": false,
2879
2895
  "repeatEvery": 1.5
2880
2896
  }
2881
- }
2897
+ },
2898
+ "uid": "n_sfo65nky8me2m1lr"
2882
2899
  },
2883
2900
  {
2884
2901
  "name": "RoarSfx",
@@ -2892,7 +2909,8 @@
2892
2909
  "maxDistance": 90
2893
2910
  }
2894
2911
  }
2895
- ]
2912
+ ],
2913
+ "uid": "n_er3epyju7e5xopzg"
2896
2914
  },
2897
2915
  {
2898
2916
  "name": "Camera",
@@ -2997,7 +3015,8 @@
2997
3015
  }
2998
3016
  ]
2999
3017
  }
3000
- ]
3018
+ ],
3019
+ "uid": "n_ndhsdrkhi26aksvr"
3001
3020
  },
3002
3021
  "connections": [
3003
3022
  {
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@dimforge/rapier2d-compat": "0.19.3",
14
- "incanto": "^0.65.0",
14
+ "incanto": "^0.67.0",
15
15
  "three": "^0.184.0"
16
16
  },
17
17
  "devDependencies": {