incanto 0.57.0 → 0.59.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 (96) hide show
  1. package/README.md +6 -4
  2. package/bin/incanto-check.mjs +27 -0
  3. package/bin/incanto-multiplay.mjs +170 -0
  4. package/bin/incanto-new.mjs +29 -7
  5. package/bin/incanto-playtest.mjs +28 -2
  6. package/bin/incanto-verify.mjs +155 -19
  7. package/bin/incanto.mjs +107 -0
  8. package/dist/2d.d.ts +8 -2
  9. package/dist/2d.js +3 -3
  10. package/dist/3d.d.ts +9 -3
  11. package/dist/3d.js +4 -4
  12. package/dist/{behavior-l08AEbq9.d.ts → behavior-DWKTUzKI.d.ts} +10 -0
  13. package/dist/{create-game-C5jQYPah.js → create-game-BiW8Men_.js} +61 -13
  14. package/dist/{create-game-DpbUrMOQ.js → create-game-CHDLDQsQ.js} +6 -6
  15. package/dist/debug.d.ts +1 -1
  16. package/dist/debug.js +2 -2
  17. package/dist/{duplicate-BPLZDZpd.js → duplicate-DJQd44CD.js} +1 -1
  18. package/dist/{environment-presets-CvvQr_bJ.js → environment-presets-DRAz5EV9.js} +12 -10
  19. package/dist/{gameplay-BVphcxmE.js → gameplay-BBEjPFsR.js} +62 -34
  20. package/dist/gameplay.d.ts +1 -1
  21. package/dist/gameplay.js +1 -1
  22. package/dist/index.d.ts +36 -8
  23. package/dist/index.js +8 -8
  24. package/dist/{json-BLk7H2Qa.js → json-CwwhxQgb.js} +7 -1
  25. package/dist/{loader-BcrRSjxB.js → loader-D8n7TU8W.js} +142 -5
  26. package/dist/{loader-BbEMTuWg.d.ts → loader-TvkRFbyL.d.ts} +1 -1
  27. package/dist/net.d.ts +2 -2
  28. package/dist/net.js +1 -1
  29. package/dist/{pathfinding-mEN4V1CU.d.ts → pathfinding-BqWBb0kh.d.ts} +1 -1
  30. package/dist/{physics-2d-BLcvEFDR.js → physics-2d-BaRSRrrZ.js} +14 -3
  31. package/dist/{physics-3d-QBrfIT2Y.js → physics-3d-CYxjh-HW.js} +15 -4
  32. package/dist/quiet-rapier-BAJ4K94N.js +46 -0
  33. package/dist/react.d.ts +1 -1
  34. package/dist/react.js +2 -2
  35. package/dist/{register-C6ZBFRjd.js → register-BpFcgdcL.js} +57 -27
  36. package/dist/{register-Ch70uByv.js → register-CDrAQqPp.js} +90 -41
  37. package/dist/{registry-C7u42TID.js → registry-WWcQcfMr.js} +1 -1
  38. package/dist/{replay-s7I2GstT.js → replay-CEPyQtF_.js} +31 -7
  39. package/dist/{replay-Dw6gMlYA.d.ts → replay-O-yAGM76.d.ts} +1 -1
  40. package/dist/{split-screen-B0baBwxI.d.ts → split-screen-BQ3tAsf-.d.ts} +38 -1
  41. package/dist/{split-screen-DLsUrleX.js → split-screen-DDMZutQ6.js} +56 -13
  42. package/dist/{sprite-animation-C0wXLBZJ.js → sprite-animation-CY-mrr1L.js} +1 -1
  43. package/dist/{src-CGjmPw65.js → src-CY21B462.js} +1 -1
  44. package/dist/{teardown-Cs113S9F.js → teardown-RApWnM1G.js} +1 -1
  45. package/dist/{test-it1VekWs.js → test-DHYuFyAu.js} +292 -31
  46. package/dist/test.d.ts +104 -6
  47. package/dist/test.js +3 -3
  48. package/dist/vite.js +2 -2
  49. package/editor/assets/{agent8-CGT7r3Mb.js → agent8-BoRGtVxK.js} +1 -1
  50. package/editor/assets/{debug-BxWSIHG3.js → debug-CzdyCg75.js} +1 -1
  51. package/editor/assets/{index-CV1m-aX5.js → index-VesuVEhe.js} +91 -91
  52. package/editor/index.html +1 -1
  53. package/package.json +3 -1
  54. package/schemas/scene.schema.json +1174 -70
  55. package/skills/incanto-building-2d-games.md +13 -0
  56. package/skills/incanto-building-3d-games.md +3 -3
  57. package/skills/incanto-localization.md +40 -8
  58. package/skills/incanto-multiplayer.md +57 -4
  59. package/skills/incanto-node-reference.md +18 -0
  60. package/skills/incanto-physics-and-input.md +26 -0
  61. package/skills/incanto-playtesting.md +19 -5
  62. package/skills/incanto-verifying-your-game.md +33 -4
  63. package/templates-app/beacon-isle-3d/package.json +1 -1
  64. package/templates-app/beacon-isle-3d/src/game.scene.json +7 -6
  65. package/templates-app/platformer-2d/PROJECT/Context.md +70 -0
  66. package/templates-app/platformer-2d/PROJECT/Requirements.md +63 -0
  67. package/templates-app/platformer-2d/PROJECT/Status.md +60 -0
  68. package/templates-app/platformer-2d/PROJECT/Structure.md +77 -0
  69. package/templates-app/platformer-2d/docs/project-2d-rules.md +61 -0
  70. package/templates-app/platformer-2d/index.html +99 -0
  71. package/templates-app/platformer-2d/package.json +23 -0
  72. package/templates-app/platformer-2d/src/behaviors.ts +541 -0
  73. package/templates-app/platformer-2d/src/game.scene.json +2061 -0
  74. package/templates-app/platformer-2d/src/main.ts +68 -0
  75. package/templates-app/platformer-2d/tsconfig.json +13 -0
  76. package/templates-app/platformer-2d/verify.ts +275 -0
  77. package/templates-app/platformer-2d/vite.config.ts +12 -0
  78. package/templates-app/star-survivor/PROJECT/Context.md +55 -0
  79. package/templates-app/star-survivor/PROJECT/Requirements.md +47 -0
  80. package/templates-app/star-survivor/PROJECT/Status.md +44 -0
  81. package/templates-app/star-survivor/PROJECT/Structure.md +63 -0
  82. package/templates-app/star-survivor/docs/project-2d-rules.md +53 -0
  83. package/templates-app/star-survivor/index.html +232 -0
  84. package/templates-app/star-survivor/package.json +23 -0
  85. package/templates-app/star-survivor/src/behaviors.ts +624 -0
  86. package/templates-app/star-survivor/src/game.scene.json +464 -0
  87. package/templates-app/star-survivor/src/main.ts +49 -0
  88. package/templates-app/star-survivor/tsconfig.json +13 -0
  89. package/templates-app/star-survivor/verify.ts +193 -0
  90. package/templates-app/star-survivor/vite.config.ts +12 -0
  91. package/templates-app/tps-3d/package.json +1 -1
  92. package/templates-app/tps-3d/src/game.scene.json +6 -3
  93. package/templates-app/tps-3d/verify.ts +17 -1
  94. package/templates-app/village-quest-3d/package.json +1 -1
  95. package/templates-app/village-quest-3d/src/grove.scene.json +14 -13
  96. package/templates-app/village-quest-3d/src/village.scene.json +5 -5
@@ -0,0 +1,464 @@
1
+ {
2
+ "format": 1,
3
+ "type": "scene",
4
+ "dimension": "2d",
5
+ "name": "HollowHorde",
6
+ "environment": {
7
+ "background": "#0d1022"
8
+ },
9
+ "viewport": {
10
+ "design": [960, 540],
11
+ "fit": "expand"
12
+ },
13
+ "physics": {
14
+ "gravity": [0, 0]
15
+ },
16
+ "input": {
17
+ "move": {
18
+ "type": "vector2",
19
+ "keys": {
20
+ "up": ["KeyW", "ArrowUp"],
21
+ "down": ["KeyS", "ArrowDown"],
22
+ "left": ["KeyA", "ArrowLeft"],
23
+ "right": ["KeyD", "ArrowRight"]
24
+ },
25
+ "touch": "joystick"
26
+ }
27
+ },
28
+ "assets": {
29
+ "knight": {
30
+ "type": "spritesheet",
31
+ "url": "incanto/assets/characters/medieval-knight.png",
32
+ "frameWidth": 192,
33
+ "frameHeight": 192,
34
+ "filter": "nearest",
35
+ "source": "built-in 'medieval-knight' \u2014 idle 0-5, move 6-11. URL injected in main.ts."
36
+ },
37
+ "goblin": {
38
+ "type": "spritesheet",
39
+ "url": "incanto/assets/characters/goblin.png",
40
+ "frameWidth": 192,
41
+ "frameHeight": 192,
42
+ "filter": "nearest",
43
+ "source": "built-in 'goblin' \u2014 idle 0-6, move 7-12. URL injected in main.ts."
44
+ },
45
+ "ghost": {
46
+ "type": "spritesheet",
47
+ "url": "incanto/assets/characters/ghost.png",
48
+ "frameWidth": 112,
49
+ "frameHeight": 128,
50
+ "filter": "nearest",
51
+ "source": "built-in 'ghost' \u2014 idle 0-5, move 6-11. URL injected in main.ts."
52
+ }
53
+ },
54
+ "root": {
55
+ "name": "Game",
56
+ "type": "Node",
57
+ "script": {
58
+ "name": "ScoreKeeper",
59
+ "props": {
60
+ "scoreToWin": 1,
61
+ "lives": 1
62
+ }
63
+ },
64
+ "children": [
65
+ {
66
+ "name": "Floor",
67
+ "type": "Node2D",
68
+ "props": {
69
+ "position": [0, 0]
70
+ },
71
+ "script": {
72
+ "name": "GridFloor",
73
+ "props": {
74
+ "color": "#12152a",
75
+ "line": "#1d244a",
76
+ "cell": 200,
77
+ "lines": 26
78
+ }
79
+ }
80
+ },
81
+ {
82
+ "name": "Player",
83
+ "type": "CharacterBody2D",
84
+ "groups": ["player"],
85
+ "props": {
86
+ "position": [0, 0],
87
+ "collider": {
88
+ "shape": "circle",
89
+ "radius": 15
90
+ }
91
+ },
92
+ "script": {
93
+ "name": "Survivor"
94
+ },
95
+ "children": [
96
+ {
97
+ "name": "Skin",
98
+ "type": "AnimatedSprite2D",
99
+ "props": {
100
+ "sheet": "$knight",
101
+ "autoplay": "idle",
102
+ "scale": [0.46, 0.46],
103
+ "anchor": [0.5, 0.56],
104
+ "animations": {
105
+ "idle": {
106
+ "frames": [0, 5],
107
+ "fps": 10,
108
+ "loop": true
109
+ },
110
+ "move": {
111
+ "frames": [6, 11],
112
+ "fps": 14,
113
+ "loop": true
114
+ }
115
+ }
116
+ }
117
+ },
118
+ {
119
+ "name": "Vitals",
120
+ "type": "Node2D",
121
+ "script": {
122
+ "name": "Health",
123
+ "props": {
124
+ "max": 100,
125
+ "invulnerableFor": 0.6
126
+ }
127
+ },
128
+ "uid": "n_bk99wi475y8y1c1g"
129
+ }
130
+ ]
131
+ },
132
+ {
133
+ "name": "GoblinSpawner",
134
+ "type": "Node2D",
135
+ "props": {
136
+ "position": [0, 0]
137
+ },
138
+ "script": {
139
+ "name": "Spawner",
140
+ "props": {
141
+ "prefab": "GoblinTemplate",
142
+ "interval": 1.3,
143
+ "max": 44,
144
+ "total": 0
145
+ }
146
+ },
147
+ "children": [
148
+ {
149
+ "name": "GoblinTemplate",
150
+ "type": "CharacterBody2D",
151
+ "groups": ["enemy"],
152
+ "props": {
153
+ "position": [0, 0],
154
+ "visible": false,
155
+ "collider": {
156
+ "shape": "circle",
157
+ "radius": 15
158
+ }
159
+ },
160
+ "script": {
161
+ "name": "Health",
162
+ "props": {
163
+ "max": 3,
164
+ "freeOnDeath": true
165
+ }
166
+ },
167
+ "children": [
168
+ {
169
+ "name": "Skin",
170
+ "type": "AnimatedSprite2D",
171
+ "props": {
172
+ "sheet": "$goblin",
173
+ "autoplay": "move",
174
+ "scale": [0.4, 0.4],
175
+ "anchor": [0.5, 0.58],
176
+ "animations": {
177
+ "idle": {
178
+ "frames": [0, 6],
179
+ "fps": 9,
180
+ "loop": true
181
+ },
182
+ "move": {
183
+ "frames": [7, 12],
184
+ "fps": 12,
185
+ "loop": true
186
+ }
187
+ }
188
+ }
189
+ },
190
+ {
191
+ "name": "AI",
192
+ "type": "Node2D",
193
+ "script": {
194
+ "name": "Chase",
195
+ "props": {
196
+ "target": "/root/Player",
197
+ "speed": 62,
198
+ "moveParent": true
199
+ }
200
+ }
201
+ },
202
+ {
203
+ "name": "Face",
204
+ "type": "Node2D",
205
+ "script": {
206
+ "name": "EnemyFace"
207
+ }
208
+ },
209
+ {
210
+ "name": "Hit",
211
+ "type": "Area2D",
212
+ "props": {
213
+ "collider": {
214
+ "shape": "circle",
215
+ "radius": 18
216
+ }
217
+ },
218
+ "script": {
219
+ "name": "DamageOnContact",
220
+ "props": {
221
+ "amount": 8,
222
+ "targetGroup": "player",
223
+ "oncePerTarget": false
224
+ }
225
+ }
226
+ },
227
+ {
228
+ "name": "Drop",
229
+ "type": "Node2D",
230
+ "script": {
231
+ "name": "EnemyDrop",
232
+ "props": {
233
+ "xp": 1,
234
+ "color": "#ff8a5b"
235
+ }
236
+ }
237
+ }
238
+ ],
239
+ "uid": "n_la5pj943qw63cztp"
240
+ }
241
+ ]
242
+ },
243
+ {
244
+ "name": "GhostSpawner",
245
+ "type": "Node2D",
246
+ "props": {
247
+ "position": [0, 0]
248
+ },
249
+ "script": {
250
+ "name": "Spawner",
251
+ "props": {
252
+ "prefab": "GhostTemplate",
253
+ "interval": 2.8,
254
+ "max": 22,
255
+ "total": 0
256
+ }
257
+ },
258
+ "children": [
259
+ {
260
+ "name": "GhostTemplate",
261
+ "type": "CharacterBody2D",
262
+ "groups": ["enemy"],
263
+ "props": {
264
+ "position": [0, 0],
265
+ "visible": false,
266
+ "collider": {
267
+ "shape": "circle",
268
+ "radius": 14
269
+ }
270
+ },
271
+ "script": {
272
+ "name": "Health",
273
+ "props": {
274
+ "max": 5,
275
+ "freeOnDeath": true
276
+ }
277
+ },
278
+ "children": [
279
+ {
280
+ "name": "Skin",
281
+ "type": "AnimatedSprite2D",
282
+ "props": {
283
+ "sheet": "$ghost",
284
+ "autoplay": "move",
285
+ "scale": [0.6, 0.6],
286
+ "anchor": [0.5, 0.6],
287
+ "opacity": 0.92,
288
+ "animations": {
289
+ "idle": {
290
+ "frames": [0, 5],
291
+ "fps": 9,
292
+ "loop": true
293
+ },
294
+ "move": {
295
+ "frames": [6, 11],
296
+ "fps": 12,
297
+ "loop": true
298
+ }
299
+ }
300
+ }
301
+ },
302
+ {
303
+ "name": "AI",
304
+ "type": "Node2D",
305
+ "script": {
306
+ "name": "Chase",
307
+ "props": {
308
+ "target": "/root/Player",
309
+ "speed": 98,
310
+ "moveParent": true
311
+ }
312
+ }
313
+ },
314
+ {
315
+ "name": "Face",
316
+ "type": "Node2D",
317
+ "script": {
318
+ "name": "EnemyFace"
319
+ }
320
+ },
321
+ {
322
+ "name": "Hit",
323
+ "type": "Area2D",
324
+ "props": {
325
+ "collider": {
326
+ "shape": "circle",
327
+ "radius": 16
328
+ }
329
+ },
330
+ "script": {
331
+ "name": "DamageOnContact",
332
+ "props": {
333
+ "amount": 12,
334
+ "targetGroup": "player",
335
+ "oncePerTarget": false
336
+ }
337
+ }
338
+ },
339
+ {
340
+ "name": "Drop",
341
+ "type": "Node2D",
342
+ "script": {
343
+ "name": "EnemyDrop",
344
+ "props": {
345
+ "xp": 2,
346
+ "color": "#8fd0ff"
347
+ }
348
+ }
349
+ }
350
+ ],
351
+ "uid": "n_2ntnqo7i21w7ci8x"
352
+ }
353
+ ]
354
+ },
355
+ {
356
+ "name": "Director",
357
+ "type": "Node2D",
358
+ "script": {
359
+ "name": "Director",
360
+ "props": {
361
+ "spawners": ["/root/GoblinSpawner", "/root/GhostSpawner"],
362
+ "ringMin": 380,
363
+ "ringMax": 560
364
+ }
365
+ }
366
+ },
367
+ {
368
+ "name": "Camera",
369
+ "type": "Camera2D",
370
+ "props": {
371
+ "current": true
372
+ },
373
+ "script": {
374
+ "name": "FollowCamera",
375
+ "props": {
376
+ "target": "/root/Player",
377
+ "smoothing": 0.86
378
+ }
379
+ }
380
+ },
381
+ {
382
+ "name": "SfxShoot",
383
+ "type": "AudioPlayer",
384
+ "props": {
385
+ "preset": "shoot",
386
+ "bus": "sfx",
387
+ "volume": 0.28
388
+ }
389
+ },
390
+ {
391
+ "name": "SfxXp",
392
+ "type": "AudioPlayer",
393
+ "props": {
394
+ "preset": "coin",
395
+ "bus": "sfx",
396
+ "volume": 0.4
397
+ }
398
+ },
399
+ {
400
+ "name": "SfxKill",
401
+ "type": "AudioPlayer",
402
+ "props": {
403
+ "preset": "hit",
404
+ "bus": "sfx",
405
+ "volume": 0.3
406
+ }
407
+ },
408
+ {
409
+ "name": "SfxHurt",
410
+ "type": "AudioPlayer",
411
+ "props": {
412
+ "preset": "hurt",
413
+ "bus": "sfx",
414
+ "volume": 0.55
415
+ }
416
+ },
417
+ {
418
+ "name": "SfxWin",
419
+ "type": "AudioPlayer",
420
+ "props": {
421
+ "preset": "win",
422
+ "bus": "sfx",
423
+ "volume": 0.8
424
+ }
425
+ },
426
+ {
427
+ "name": "SfxLose",
428
+ "type": "AudioPlayer",
429
+ "props": {
430
+ "preset": "lose",
431
+ "bus": "sfx",
432
+ "volume": 0.8
433
+ }
434
+ }
435
+ ],
436
+ "uid": "n_tlqu945vs98khzn8"
437
+ },
438
+ "connections": [
439
+ {
440
+ "signal": "died",
441
+ "from": "Player/Vitals",
442
+ "to": "/root",
443
+ "handler": "loseLife"
444
+ },
445
+ {
446
+ "signal": "damaged",
447
+ "from": "Player/Vitals",
448
+ "to": "SfxHurt",
449
+ "handler": "play"
450
+ },
451
+ {
452
+ "signal": "won",
453
+ "from": "/root",
454
+ "to": "SfxWin",
455
+ "handler": "play"
456
+ },
457
+ {
458
+ "signal": "lost",
459
+ "from": "/root",
460
+ "to": "SfxLose",
461
+ "handler": "play"
462
+ }
463
+ ]
464
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Hollow Horde — a top-down SURVIVORS-LIKE (Vampire Survivors genre) on Incanto.
3
+ * Move with WASD / arrows; your knight AUTO-ATTACKS the nearest enemy. Goblins and
4
+ * faster ghosts pour in from every side and grow tougher over time. Cut them down,
5
+ * vacuum up the XP shards they drop, and on each LEVEL-UP pick one of three
6
+ * upgrades. Survive 90 seconds to win — let the horde drain your HP and you fall.
7
+ *
8
+ * The horde is BUILT-IN gameplay wired in `game.scene.json`: two `Spawner`s clone
9
+ * goblin/ghost templates, each enemy `Chase`s the player, and a `DamageOnContact`
10
+ * hitbox drains `Health`. The custom TypeScript is the survivor FEEL the library
11
+ * leaves open: `Survivor` (move + auto-attack + XP/level-up/upgrades + HUD),
12
+ * `Director` (ring-spawn around the player + escalation), `EnemyDrop`, `EnemyFace`.
13
+ */
14
+ import { createGame2D } from 'incanto/2d';
15
+ import ghostUrl from 'incanto/assets/characters/ghost.png';
16
+ import goblinUrl from 'incanto/assets/characters/goblin.png';
17
+ import knightUrl from 'incanto/assets/characters/medieval-knight.png';
18
+ import { Director, EnemyDrop, EnemyFace, GridFloor, Survivor } from './behaviors';
19
+ import sceneJson from './game.scene.json';
20
+
21
+ const MUSIC_URL = '';
22
+
23
+ const behaviors = { Survivor, Director, EnemyDrop, EnemyFace, GridFloor };
24
+
25
+ const canvas = document.querySelector('canvas') as HTMLCanvasElement;
26
+
27
+ const scene = structuredClone(sceneJson) as typeof sceneJson & {
28
+ assets: { knight: { url: string }; goblin: { url: string }; ghost: { url: string } };
29
+ };
30
+ scene.assets.knight.url = knightUrl;
31
+ scene.assets.goblin.url = goblinUrl;
32
+ scene.assets.ghost.url = ghostUrl;
33
+
34
+ const game = await createGame2D({
35
+ debug: import.meta.env.VITE_INCANTO_DEBUG === '1',
36
+ canvas,
37
+ scene,
38
+ behaviors,
39
+ });
40
+
41
+ document.querySelector('#loading')?.remove();
42
+
43
+ if (MUSIC_URL) {
44
+ game.engine.music.play(MUSIC_URL, { loop: true, fadeIn: 1.5 });
45
+ game.engine.audio.music = 0.3;
46
+ }
47
+
48
+ // Console playground: game.scene.root.getNode('Player').position = [x, y]
49
+ Object.assign(window, { game });
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "skipLibCheck": true,
9
+ "resolveJsonModule": true,
10
+ "types": ["vite/client", "node"]
11
+ },
12
+ "include": ["src", "verify.ts"]
13
+ }