incanto 0.68.0 → 0.70.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 (153) hide show
  1. package/assets/catalog.json +9 -5
  2. package/bin/_behaviors-loader.mjs +22 -0
  3. package/bin/_read-json.mjs +28 -0
  4. package/bin/incanto-assets.mjs +19 -5
  5. package/bin/incanto-check.mjs +92 -15
  6. package/bin/incanto-editor.mjs +128 -5
  7. package/bin/incanto-env.mjs +3 -2
  8. package/bin/incanto-feel.mjs +24 -13
  9. package/bin/incanto-frame.mjs +8 -1
  10. package/bin/incanto-multiplay.mjs +11 -9
  11. package/bin/incanto-new.mjs +128 -5
  12. package/bin/incanto-play.mjs +158 -16
  13. package/bin/incanto-playtest.mjs +66 -23
  14. package/bin/incanto-serve.mjs +160 -0
  15. package/bin/incanto-skills.mjs +14 -2
  16. package/bin/incanto-verify.mjs +165 -44
  17. package/bin/incanto.mjs +4 -2
  18. package/dist/2d.d.ts +285 -36
  19. package/dist/2d.js +4 -4
  20. package/dist/3d.d.ts +158 -10
  21. package/dist/3d.js +8 -8
  22. package/dist/{agent8-CvsfVskX.js → agent8-CmNF01gA.js} +61 -8
  23. package/dist/{audio-player-DOrq7sP-.d.ts → audio-player-DaMxqfNE.d.ts} +33 -14
  24. package/dist/{behavior-DoFPYrgo.d.ts → behavior-DZExDn9o.d.ts} +809 -44
  25. package/dist/{create-game-IZIydDwI.js → create-game-Bwvh6q8A.js} +148 -61
  26. package/dist/{create-game-DbWtVTxD.js → create-game-C7ffQWW7.js} +103 -49
  27. package/dist/debug.d.ts +1 -1
  28. package/dist/debug.js +2 -3
  29. package/dist/diagnostics-Cu85N3tL.d.ts +12 -0
  30. package/dist/{editor-switch-CnIOiyNJ.d.ts → editor-switch-CFU9mCec.d.ts} +22 -13
  31. package/dist/editor.js +1066 -864
  32. package/dist/env.d.ts +1 -1
  33. package/dist/env.js +5 -3
  34. package/dist/{environment-presets-CybQXNqS.js → environment-presets-D6Q5BxeE.js} +299 -46
  35. package/dist/{frame-report-DCnHFmto.d.ts → frame-report-DNxDAb1w.d.ts} +8 -0
  36. package/dist/{frame-report-BSMny7oe.js → frame-report-Dlq13Gyj.js} +1 -0
  37. package/dist/{gameplay-DM1eu_cV.js → gameplay-BfHkuzVb.js} +825 -221
  38. package/dist/gameplay.d.ts +187 -7
  39. package/dist/gameplay.js +1 -1
  40. package/dist/{heightmap-CRK0M4jT.js → heightmap-BYgD5Edk.js} +1 -1
  41. package/dist/index.d.ts +156 -13
  42. package/dist/index.js +10 -12
  43. package/dist/json-CfTjpvW8.js +67 -0
  44. package/dist/{loader-CcB533FR.d.ts → loader-Cff09LMm.d.ts} +2 -2
  45. package/dist/net.d.ts +27 -3
  46. package/dist/net.js +2 -2
  47. package/dist/{noise-CGUMx44x.js → noise-D3nPpmFg.js} +1 -1
  48. package/dist/{physics-2d-B7Y6dPZO.js → physics-2d-CE0Qvy3V.js} +136 -11
  49. package/dist/{physics-3d-bG3n70Ky.js → physics-3d-CpH-2gn5.js} +104 -23
  50. package/dist/{teardown-D2NEmxPB.js → picking-CQJ_PJKh.js} +106 -14
  51. package/dist/react.d.ts +2 -2
  52. package/dist/react.js +2 -2
  53. package/dist/{register-3ta-2Xig.js → register-6DYnKZcy.js} +652 -831
  54. package/dist/{register-ibCjm-wH.js → register-Bkk0wSDB.js} +348 -30
  55. package/dist/{replay-CYvhVHHN.js → replay-DjAkAzMq.js} +224 -14
  56. package/dist/{replay-Dvn8aeBd.d.ts → replay-Dmw-PKQu.d.ts} +20 -3
  57. package/dist/{schema-B6ugCV1Q.d.ts → rng-Bb-IutXB.d.ts} +38 -21
  58. package/dist/{rng-DP-SR7eg.js → rng-CDOMybym.js} +22 -0
  59. package/dist/{loader-BC4PNtJX.js → save-slots-BXVg148r.js} +4558 -2294
  60. package/dist/{sheet-grid-BT6N_Bjs.js → sheet-grid-Cea343VO.js} +6 -2
  61. package/dist/{split-screen-DhrSzZIB.d.ts → split-screen--k-XpBjr.d.ts} +36 -4
  62. package/dist/{split-screen-CYwDkbLF.js → split-screen-PL78oVXP.js} +159 -26
  63. package/dist/{sprite-animation-CY-mrr1L.js → sprite-animation-CqR2o3SA.js} +39 -8
  64. package/dist/{src-D7RIqXYF.js → src-Cxfiv1Hg.js} +2 -17
  65. package/dist/test-iHYVUcDK.js +4036 -0
  66. package/dist/test.d.ts +542 -30
  67. package/dist/test.js +3 -3
  68. package/dist/touch-BnCyPA0G.js +519 -0
  69. package/dist/vite.d.ts +54 -3
  70. package/dist/vite.js +349 -17
  71. package/dist/{webgl-unavailable-N9nQqesw.js → webgl-unavailable-C8aDbGmR.js} +56 -1
  72. package/editor/assets/agent8-D0MS174y.js +1 -0
  73. package/editor/assets/{debug-BBhKuBNV.js → debug-BnXkKuYu.js} +2 -2
  74. package/editor/assets/index-CIu3uc3l.js +11046 -0
  75. package/editor/index.html +1 -1
  76. package/package.json +7 -16
  77. package/schemas/scene.schema.json +30 -3
  78. package/skills/incanto-3d-character.md +14 -1
  79. package/skills/incanto-3d-models.md +12 -0
  80. package/skills/incanto-assets.md +25 -3
  81. package/skills/incanto-audio.md +27 -5
  82. package/skills/incanto-behaviors-and-scripts.md +83 -6
  83. package/skills/incanto-building-2d-games.md +106 -8
  84. package/skills/incanto-building-3d-games.md +118 -6
  85. package/skills/incanto-editor.md +46 -7
  86. package/skills/incanto-environment.md +19 -1
  87. package/skills/incanto-game-feel.md +70 -0
  88. package/skills/incanto-gameplay-behaviors.md +121 -14
  89. package/skills/incanto-hud.md +128 -7
  90. package/skills/incanto-localization.md +13 -5
  91. package/skills/incanto-multiplayer.md +83 -3
  92. package/skills/incanto-node-reference.md +222 -58
  93. package/skills/incanto-performance.md +52 -0
  94. package/skills/incanto-physics-and-input.md +123 -24
  95. package/skills/incanto-playtesting.md +78 -2
  96. package/skills/incanto-save-slots.md +188 -6
  97. package/skills/incanto-scene-json-authoring.md +69 -12
  98. package/skills/incanto-verifying-your-game.md +292 -12
  99. package/skills/incanto-web-integration.md +28 -0
  100. package/skills/incanto-your-first-game.md +5 -2
  101. package/templates-app/beacon-isle-3d/generate-world.ts +77 -9
  102. package/templates-app/beacon-isle-3d/package.json +2 -2
  103. package/templates-app/beacon-isle-3d/src/behaviors.ts +22 -0
  104. package/templates-app/beacon-isle-3d/src/game.scene.json +103 -378
  105. package/templates-app/beacon-isle-3d/src/main.ts +24 -4
  106. package/templates-app/beacon-isle-3d/tsconfig.json +1 -1
  107. package/templates-app/beacon-isle-3d/verify.ts +3 -1
  108. package/templates-app/molehill-2d/.incanto/playtest/lost-seed1.json +4277 -0
  109. package/templates-app/molehill-2d/PROJECT/Context.md +58 -0
  110. package/templates-app/molehill-2d/PROJECT/Requirements.md +39 -0
  111. package/templates-app/molehill-2d/PROJECT/Status.md +27 -0
  112. package/templates-app/molehill-2d/PROJECT/Structure.md +48 -0
  113. package/templates-app/molehill-2d/docs/project-2d-rules.md +44 -0
  114. package/templates-app/molehill-2d/index.html +73 -0
  115. package/templates-app/molehill-2d/package.json +23 -0
  116. package/templates-app/molehill-2d/src/behaviors.ts +198 -0
  117. package/templates-app/molehill-2d/src/game.scene.json +1255 -0
  118. package/templates-app/molehill-2d/src/main.ts +41 -0
  119. package/templates-app/molehill-2d/tsconfig.json +13 -0
  120. package/templates-app/molehill-2d/verify.ts +247 -0
  121. package/templates-app/molehill-2d/vite.config.ts +12 -0
  122. package/templates-app/platformer-2d/index.html +0 -23
  123. package/templates-app/platformer-2d/package.json +2 -2
  124. package/templates-app/platformer-2d/src/behaviors.ts +26 -16
  125. package/templates-app/platformer-2d/src/game.scene.json +143 -625
  126. package/templates-app/platformer-2d/src/main.ts +35 -13
  127. package/templates-app/platformer-2d/tsconfig.json +1 -1
  128. package/templates-app/star-survivor/package.json +2 -2
  129. package/templates-app/star-survivor/src/game.scene.json +41 -195
  130. package/templates-app/star-survivor/src/main.ts +28 -7
  131. package/templates-app/star-survivor/tsconfig.json +1 -1
  132. package/templates-app/tps-3d/PROJECT/Context.md +1 -1
  133. package/templates-app/tps-3d/package.json +2 -2
  134. package/templates-app/tps-3d/src/behaviors.ts +19 -1
  135. package/templates-app/tps-3d/src/game.scene.json +78 -217
  136. package/templates-app/tps-3d/src/main.ts +39 -17
  137. package/templates-app/tps-3d/tsconfig.json +1 -1
  138. package/templates-app/village-quest-3d/.incanto/playtest/swapped-seed1.json +1735 -0
  139. package/templates-app/village-quest-3d/package.json +2 -2
  140. package/templates-app/village-quest-3d/src/behaviors.ts +21 -0
  141. package/templates-app/village-quest-3d/src/grove.scene.json +54 -221
  142. package/templates-app/village-quest-3d/src/main.ts +24 -4
  143. package/templates-app/village-quest-3d/src/village.scene.json +199 -838
  144. package/templates-app/village-quest-3d/tsconfig.json +1 -1
  145. package/templates-app/village-quest-3d/verify.ts +14 -1
  146. package/dist/duplicate-IWIqk0HJ.js +0 -22
  147. package/dist/json-CwwhxQgb.js +0 -36
  148. package/dist/registry-CF70EArN.js +0 -212
  149. package/dist/rolldown-runtime-D7D4PA-g.js +0 -13
  150. package/dist/test-8hoHeRmo.js +0 -2340
  151. package/dist/touch-DEAmqGdf.js +0 -225
  152. package/editor/assets/agent8-BrrHOjMJ.js +0 -1
  153. package/editor/assets/index-eVd0BToA.js +0 -10958
@@ -6,14 +6,14 @@
6
6
  "dev": "vite",
7
7
  "build": "vite build",
8
8
  "typecheck": "tsc --noEmit",
9
- "check": "incanto-check src",
9
+ "check": "incanto-check src --behaviors src/behaviors.ts",
10
10
  "verify": "bun verify.ts"
11
11
  },
12
12
  "dependencies": {
13
13
  "@dimforge/rapier2d-compat": "0.19.3",
14
14
  "@dimforge/rapier3d-compat": "0.19.3",
15
15
  "@pixiv/three-vrm": "^3.5.3",
16
- "incanto": "^0.68.0",
16
+ "incanto": "^0.70.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {
@@ -161,6 +161,16 @@ function ambientUpdate(
161
161
  // ---- VillageDirector --------------------------------------------------------------
162
162
 
163
163
  export class VillageDirector extends Behavior {
164
+ /**
165
+ * `QUEST COMPLETE` was a banner and nothing else.
166
+ *
167
+ * The village had an ending — the wolves cleared, the Elder's thanks, a
168
+ * restart button — and emitted no `won`, so the playtest reported
169
+ * `no win declared in this scene — nothing emits won/lost, so there is
170
+ * nothing to reach` about a game that has one. The same shape as the isle's.
171
+ */
172
+ static readonly signals: readonly string[] = ['won'];
173
+
164
174
  private wind: Voice | null = null;
165
175
  private gateHinted = false;
166
176
 
@@ -196,6 +206,16 @@ export class VillageDirector extends Behavior {
196
206
  if (engine && this.dialogue.active && engine.input.justPressed('interact')) {
197
207
  this.dialogue.advance();
198
208
  }
209
+ /*
210
+ * R restarts once the quest is done — the same thing the button does.
211
+ *
212
+ * The scene has always declared `"restart": { "keys": ["KeyR"] }` and
213
+ * nothing read it, so this game's own control vocabulary promised a key
214
+ * that did nothing. `incanto-playtest` now says so:
215
+ * `declared and never read: \`restart\``.
216
+ */
217
+ const restart = engine ? engine.input.justPressed('restart') : false;
218
+ if (restart && quest.done) this.onRestart();
199
219
  }
200
220
 
201
221
  /** Elder.interacted → here (scene connection). */
@@ -214,6 +234,7 @@ export class VillageDirector extends Behavior {
214
234
  const banner = this.node.getNode('HUD/Banner') as UiBanner;
215
235
  talk.on('dialogueFinished', () => {
216
236
  banner.show('QUEST COMPLETE');
237
+ this.node.emit('won');
217
238
  (this.node.getNode('HUD/RestartBtn') as UiButton).visible = true;
218
239
  (this.node.getNode('HUD/Quest') as UiText).text = 'Emberwood is safe.';
219
240
  });
@@ -11,33 +11,16 @@
11
11
  "turbidity": 5,
12
12
  "rayleigh": 3.2
13
13
  },
14
- "fog": {
15
- "near": 20,
16
- "far": 80
17
- },
18
- "shadows": {
19
- "mapSize": 2048
20
- },
14
+ "fog": { "near": 20, "far": 80 },
15
+ "shadows": { "mapSize": 2048 },
21
16
  "exposure": 1,
22
- "ambient": {
23
- "color": "#a8b4e0",
24
- "intensity": 0.95
25
- },
17
+ "ambient": { "color": "#a8b4e0", "intensity": 0.95 },
26
18
  "iblIntensity": 0.85,
27
19
  "background": "#141322",
28
- "post": {
29
- "vignette": 0.34,
30
- "saturation": 0.88,
31
- "contrast": 1.05
32
- },
33
- "bloom": {
34
- "threshold": 0.85,
35
- "strength": 0.5
36
- }
37
- },
38
- "physics": {
39
- "gravity": [0, -9.81, 0]
20
+ "post": { "vignette": 0.34, "saturation": 0.88, "contrast": 1.05 },
21
+ "bloom": { "threshold": 0.85, "strength": 0.5 }
40
22
  },
23
+ "physics": { "gravity": [0, -9.81, 0] },
41
24
  "input": {
42
25
  "move": {
43
26
  "type": "vector2",
@@ -48,30 +31,12 @@
48
31
  "right": ["KeyD", "ArrowRight"]
49
32
  }
50
33
  },
51
- "jump": {
52
- "type": "button",
53
- "keys": ["Space"]
54
- },
55
- "sprint": {
56
- "type": "button",
57
- "keys": ["ShiftLeft", "ShiftRight"]
58
- },
59
- "interact": {
60
- "type": "button",
61
- "keys": ["KeyE"]
62
- },
63
- "attack": {
64
- "type": "button",
65
- "keys": ["Mouse0", "KeyF"]
66
- },
67
- "restart": {
68
- "type": "button",
69
- "keys": ["KeyR"]
70
- },
71
- "pause": {
72
- "type": "button",
73
- "keys": ["Escape"]
74
- }
34
+ "jump": { "type": "button", "keys": ["Space"] },
35
+ "sprint": { "type": "button", "keys": ["ShiftLeft", "ShiftRight"] },
36
+ "interact": { "type": "button", "keys": ["KeyE"] },
37
+ "attack": { "type": "button", "keys": ["Mouse0", "KeyF"] },
38
+ "restart": { "type": "button", "keys": ["KeyR"] },
39
+ "pause": { "type": "button", "keys": ["Escape"] }
75
40
  },
76
41
  "assets": {
77
42
  "characters/base": {
@@ -106,29 +71,19 @@
106
71
  "root": {
107
72
  "name": "Game",
108
73
  "type": "Node",
109
- "script": {
110
- "name": "GroveDirector"
111
- },
74
+ "script": { "name": "GroveDirector" },
112
75
  "children": [
113
76
  {
114
77
  "name": "Flow",
115
78
  "type": "Node",
116
- "script": {
117
- "name": "GameFlow",
118
- "props": {
119
- "pausePanelPath": "%PauseMenu"
120
- }
121
- },
79
+ "script": { "name": "GameFlow", "props": { "pausePanelPath": "%PauseMenu" } },
122
80
  "uid": "n_72gl5aezorlb9d5n"
123
81
  },
124
82
  {
125
83
  "name": "Ground",
126
84
  "type": "StaticBody3D",
127
85
  "props": {
128
- "collider": {
129
- "shape": "box",
130
- "size": [40, 0.1, 32]
131
- },
86
+ "collider": { "shape": "box", "size": [40, 0.1, 32] },
132
87
  "position": [0, -0.05, 0]
133
88
  },
134
89
  "children": [
@@ -138,25 +93,17 @@
138
93
  "props": {
139
94
  "mesh": "box",
140
95
  "size": [40, 0.1, 32],
141
- "material": {
142
- "color": "#2f4030",
143
- "roughness": 1
144
- },
96
+ "material": { "color": "#2f4030", "roughness": 1 },
145
97
  "receiveShadow": true
146
98
  }
147
99
  }
148
100
  ]
149
101
  },
150
- {
151
- "name": "Maze",
152
- "type": "Node3D"
153
- },
102
+ { "name": "Maze", "type": "Node3D" },
154
103
  {
155
104
  "name": "Scenery",
156
105
  "type": "Node3D",
157
- "props": {
158
- "static": true
159
- },
106
+ "props": { "static": true },
160
107
  "children": [
161
108
  {
162
109
  "name": "Pine1",
@@ -219,13 +166,7 @@
219
166
  "name": "Wolf1",
220
167
  "type": "Node3D",
221
168
  "groups": ["wolf"],
222
- "script": {
223
- "name": "PathFollow",
224
- "props": {
225
- "speed": 2.4,
226
- "loop": true
227
- }
228
- },
169
+ "script": { "name": "PathFollow", "props": { "speed": 2.4, "loop": true } },
229
170
  "children": [
230
171
  {
231
172
  "name": "Body",
@@ -234,10 +175,7 @@
234
175
  "mesh": "box",
235
176
  "size": [0.55, 0.5, 1.3],
236
177
  "position": [0, 0, 0],
237
- "material": {
238
- "color": "#3b3b44",
239
- "roughness": 0.9
240
- },
178
+ "material": { "color": "#3b3b44", "roughness": 0.9 },
241
179
  "castShadow": true
242
180
  }
243
181
  },
@@ -248,10 +186,7 @@
248
186
  "mesh": "box",
249
187
  "size": [0.4, 0.38, 0.5],
250
188
  "position": [0, 0.18, 0.75],
251
- "material": {
252
- "color": "#46464f",
253
- "roughness": 0.9
254
- },
189
+ "material": { "color": "#46464f", "roughness": 0.9 },
255
190
  "castShadow": true
256
191
  }
257
192
  },
@@ -291,10 +226,7 @@
291
226
  "size": [0.12, 0.12, 0.55],
292
227
  "position": [0, 0.12, -0.85],
293
228
  "rotation": [-20, 0, 0],
294
- "material": {
295
- "color": "#33333b",
296
- "roughness": 0.9
297
- },
229
+ "material": { "color": "#33333b", "roughness": 0.9 },
298
230
  "castShadow": true
299
231
  }
300
232
  },
@@ -315,10 +247,7 @@
315
247
  "type": "Area3D",
316
248
  "props": {
317
249
  "position": [0, 0.1, 0.55],
318
- "collider": {
319
- "shape": "box",
320
- "size": [0.6, 0.8, 0.7]
321
- }
250
+ "collider": { "shape": "box", "size": [0.6, 0.8, 0.7] }
322
251
  },
323
252
  "script": {
324
253
  "name": "DamageOnContact",
@@ -338,13 +267,7 @@
338
267
  "name": "Wolf2",
339
268
  "type": "Node3D",
340
269
  "groups": ["wolf"],
341
- "script": {
342
- "name": "PathFollow",
343
- "props": {
344
- "speed": 2.4,
345
- "loop": true
346
- }
347
- },
270
+ "script": { "name": "PathFollow", "props": { "speed": 2.4, "loop": true } },
348
271
  "children": [
349
272
  {
350
273
  "name": "Body",
@@ -353,10 +276,7 @@
353
276
  "mesh": "box",
354
277
  "size": [0.55, 0.5, 1.3],
355
278
  "position": [0, 0, 0],
356
- "material": {
357
- "color": "#3b3b44",
358
- "roughness": 0.9
359
- },
279
+ "material": { "color": "#3b3b44", "roughness": 0.9 },
360
280
  "castShadow": true
361
281
  }
362
282
  },
@@ -367,10 +287,7 @@
367
287
  "mesh": "box",
368
288
  "size": [0.4, 0.38, 0.5],
369
289
  "position": [0, 0.18, 0.75],
370
- "material": {
371
- "color": "#46464f",
372
- "roughness": 0.9
373
- },
290
+ "material": { "color": "#46464f", "roughness": 0.9 },
374
291
  "castShadow": true
375
292
  }
376
293
  },
@@ -410,10 +327,7 @@
410
327
  "size": [0.12, 0.12, 0.55],
411
328
  "position": [0, 0.12, -0.85],
412
329
  "rotation": [-20, 0, 0],
413
- "material": {
414
- "color": "#33333b",
415
- "roughness": 0.9
416
- },
330
+ "material": { "color": "#33333b", "roughness": 0.9 },
417
331
  "castShadow": true
418
332
  }
419
333
  },
@@ -434,10 +348,7 @@
434
348
  "type": "Area3D",
435
349
  "props": {
436
350
  "position": [0, 0.1, 0.55],
437
- "collider": {
438
- "shape": "box",
439
- "size": [0.6, 0.8, 0.7]
440
- }
351
+ "collider": { "shape": "box", "size": [0.6, 0.8, 0.7] }
441
352
  },
442
353
  "script": {
443
354
  "name": "DamageOnContact",
@@ -457,13 +368,7 @@
457
368
  "name": "Wolf3",
458
369
  "type": "Node3D",
459
370
  "groups": ["wolf"],
460
- "script": {
461
- "name": "PathFollow",
462
- "props": {
463
- "speed": 2.4,
464
- "loop": true
465
- }
466
- },
371
+ "script": { "name": "PathFollow", "props": { "speed": 2.4, "loop": true } },
467
372
  "children": [
468
373
  {
469
374
  "name": "Body",
@@ -472,10 +377,7 @@
472
377
  "mesh": "box",
473
378
  "size": [0.55, 0.5, 1.3],
474
379
  "position": [0, 0, 0],
475
- "material": {
476
- "color": "#3b3b44",
477
- "roughness": 0.9
478
- },
380
+ "material": { "color": "#3b3b44", "roughness": 0.9 },
479
381
  "castShadow": true
480
382
  }
481
383
  },
@@ -486,10 +388,7 @@
486
388
  "mesh": "box",
487
389
  "size": [0.4, 0.38, 0.5],
488
390
  "position": [0, 0.18, 0.75],
489
- "material": {
490
- "color": "#46464f",
491
- "roughness": 0.9
492
- },
391
+ "material": { "color": "#46464f", "roughness": 0.9 },
493
392
  "castShadow": true
494
393
  }
495
394
  },
@@ -529,10 +428,7 @@
529
428
  "size": [0.12, 0.12, 0.55],
530
429
  "position": [0, 0.12, -0.85],
531
430
  "rotation": [-20, 0, 0],
532
- "material": {
533
- "color": "#33333b",
534
- "roughness": 0.9
535
- },
431
+ "material": { "color": "#33333b", "roughness": 0.9 },
536
432
  "castShadow": true
537
433
  }
538
434
  },
@@ -553,10 +449,7 @@
553
449
  "type": "Area3D",
554
450
  "props": {
555
451
  "position": [0, 0.1, 0.55],
556
- "collider": {
557
- "shape": "box",
558
- "size": [0.6, 0.8, 0.7]
559
- }
452
+ "collider": { "shape": "box", "size": [0.6, 0.8, 0.7] }
560
453
  },
561
454
  "script": {
562
455
  "name": "DamageOnContact",
@@ -579,10 +472,7 @@
579
472
  "type": "Area3D",
580
473
  "props": {
581
474
  "position": [3.5, 1.2, 13.5],
582
- "collider": {
583
- "shape": "box",
584
- "size": [1.8, 2.4, 0.8]
585
- }
475
+ "collider": { "shape": "box", "size": [1.8, 2.4, 0.8] }
586
476
  },
587
477
  "children": [
588
478
  {
@@ -592,10 +482,7 @@
592
482
  "mesh": "box",
593
483
  "size": [2.2, 2.8, 0.3],
594
484
  "position": [0, 0.2, 0.6],
595
- "material": {
596
- "color": "#5c4632",
597
- "roughness": 0.9
598
- },
485
+ "material": { "color": "#5c4632", "roughness": 0.9 },
599
486
  "castShadow": true
600
487
  }
601
488
  },
@@ -624,11 +511,7 @@
624
511
  "position": [0, 1.4, 13],
625
512
  "fixedRotation": true,
626
513
  "friction": 0,
627
- "collider": {
628
- "shape": "capsule",
629
- "radius": 0.34,
630
- "height": 1
631
- }
514
+ "collider": { "shape": "capsule", "radius": 0.34, "height": 1 }
632
515
  },
633
516
  "children": [
634
517
  {
@@ -648,11 +531,11 @@
648
531
  "run": "$anims/run",
649
532
  "fastRun": "$anims/runFast",
650
533
  "airborne": "$anims/jump"
651
- }
652
- },
653
- "script": {
654
- "name": "SwordStrike"
534
+ },
535
+ "coyoteSeconds": 0.12,
536
+ "jumpBufferSeconds": 0.15
655
537
  },
538
+ "script": { "name": "SwordStrike" },
656
539
  "uid": "n_9xdg9b3a5eb9r4x1"
657
540
  },
658
541
  {
@@ -669,10 +552,7 @@
669
552
  {
670
553
  "name": "SwordMount",
671
554
  "type": "BoneAttachment3D",
672
- "props": {
673
- "target": "../Skin",
674
- "bone": "RightHand"
675
- },
555
+ "props": { "target": "../Skin", "bone": "RightHand" },
676
556
  "children": [
677
557
  {
678
558
  "name": "Blade",
@@ -681,11 +561,7 @@
681
561
  "mesh": "box",
682
562
  "size": [0.045, 0.7, 0.045],
683
563
  "position": [0, 0.42, 0],
684
- "material": {
685
- "color": "#d8dde8",
686
- "metalness": 0.9,
687
- "roughness": 0.25
688
- },
564
+ "material": { "color": "#d8dde8", "metalness": 0.9, "roughness": 0.25 },
689
565
  "castShadow": true
690
566
  }
691
567
  },
@@ -696,19 +572,13 @@
696
572
  "mesh": "box",
697
573
  "size": [0.16, 0.04, 0.06],
698
574
  "position": [0, 0.09, 0],
699
- "material": {
700
- "color": "#8a6d3a",
701
- "metalness": 0.7,
702
- "roughness": 0.4
703
- }
575
+ "material": { "color": "#8a6d3a", "metalness": 0.7, "roughness": 0.4 }
704
576
  }
705
577
  },
706
578
  {
707
579
  "name": "SwordTip",
708
580
  "type": "Node3D",
709
- "props": {
710
- "position": [0, 0.78, 0]
711
- },
581
+ "props": { "position": [0, 0.78, 0] },
712
582
  "children": [
713
583
  {
714
584
  "name": "SwingTrail",
@@ -730,49 +600,27 @@
730
600
  {
731
601
  "name": "SwingSfx",
732
602
  "type": "AudioPlayer",
733
- "props": {
734
- "preset": "shoot",
735
- "volume": 0.35,
736
- "pitch": 0.55
737
- }
603
+ "props": { "preset": "shoot", "volume": 0.35, "pitch": 0.55 }
738
604
  },
739
605
  {
740
606
  "name": "HitSfx",
741
607
  "type": "AudioPlayer",
742
- "props": {
743
- "preset": "hit",
744
- "volume": 0.6
745
- }
608
+ "props": { "preset": "hit", "volume": 0.6 }
746
609
  },
747
- {
748
- "name": "Catch",
749
- "type": "Respawn"
750
- }
610
+ { "name": "Catch", "type": "Respawn" }
751
611
  ],
752
- "script": {
753
- "name": "Health",
754
- "props": {
755
- "max": 100,
756
- "invulnerableFor": 0.8
757
- }
758
- },
612
+ "script": { "name": "Health", "props": { "max": 100, "invulnerableFor": 0.8 } },
759
613
  "uid": "n_3hp4w1vicxhqr375"
760
614
  },
761
615
  {
762
616
  "name": "Camera",
763
617
  "type": "Camera3D",
764
- "props": {
765
- "current": true,
766
- "position": [0, 4, 19]
767
- }
618
+ "props": { "current": true, "position": [0, 4, 19] }
768
619
  },
769
620
  {
770
621
  "name": "WinSfx",
771
622
  "type": "AudioPlayer",
772
- "props": {
773
- "preset": "win",
774
- "volume": 0.6
775
- }
623
+ "props": { "preset": "win", "volume": 0.6 }
776
624
  },
777
625
  {
778
626
  "name": "HUD",
@@ -793,20 +641,13 @@
793
641
  "name": "HP",
794
642
  "type": "UiBar",
795
643
  "uid": "n_kdm2vun7p0o3t4l2",
796
- "props": {
797
- "anchor": "topRight",
798
- "value": 100,
799
- "max": 100,
800
- "width": 160
801
- }
644
+ "props": { "anchor": "topRight", "value": 100, "max": 100, "width": 160 }
802
645
  },
803
646
  {
804
647
  "name": "Banner",
805
648
  "type": "UiBanner",
806
649
  "uid": "n_21yz0pgnwqvz81yo",
807
- "props": {
808
- "anchor": "center"
809
- }
650
+ "props": { "anchor": "center" }
810
651
  },
811
652
  {
812
653
  "name": "Hint",
@@ -823,20 +664,12 @@
823
664
  {
824
665
  "name": "PauseMenu",
825
666
  "type": "UiPanel",
826
- "props": {
827
- "anchor": "center",
828
- "layout": "column",
829
- "gap": 10,
830
- "padding": 18
831
- },
667
+ "props": { "anchor": "center", "layout": "column", "gap": 10, "padding": 18 },
832
668
  "children": [
833
669
  {
834
670
  "name": "PausedTitle",
835
671
  "type": "UiText",
836
- "props": {
837
- "text": "Paused",
838
- "size": 24
839
- }
672
+ "props": { "text": "Paused", "size": 24 }
840
673
  },
841
674
  {
842
675
  "name": "ResumeHint",
@@ -21,8 +21,18 @@ await preloadUrls(assetUrls(villageJson.assets), (done, total) => {
21
21
  });
22
22
 
23
23
  const canvas = document.querySelector('canvas') as HTMLCanvasElement;
24
+ /** Dev-only surfaces: the ☰ debug overlay, and the editor behind it. */
25
+ const DEBUG = import.meta.env.VITE_INCANTO_DEBUG === '1';
26
+
24
27
  const game = await createGame3D({
25
- debug: import.meta.env.VITE_INCANTO_DEBUG === '1',
28
+ debug: DEBUG,
29
+ // The editor's 📚 buttons, served by `incantoLibrary()` in vite.config.ts.
30
+ // BOTH halves are the opt-in, and this half was missing from every shipped
31
+ // template: the plugin alone left a vite config whose own comment promised
32
+ // "the agent8 asset catalog behind the 📚 buttons" and no button anywhere.
33
+ // Gated on the same flag, because `editor` DEFAULTS to `debug` and an object
34
+ // here would turn the editor on in a production build.
35
+ editor: DEBUG && { library: true },
26
36
  canvas,
27
37
  scene: villageJson,
28
38
  behaviors: BEHAVIORS,
@@ -36,7 +46,17 @@ const game = await createGame3D({
36
46
  throw e;
37
47
  });
38
48
 
39
- document.querySelector('#loading')?.remove();
40
-
41
- // Console-poking handle for playtesting ("teleport me to the elder").
49
+ // The console handle FIRST, before any wiring of your own can throw.
50
+ // `game.stats()`, `game.assetErrors()`, `game.frame()` and `game.engine.log`
51
+ // are the entire in-page diagnostic surface, and a static build has no other.
52
+ // Assigned after the wiring, one mistake below took all of them with it.
42
53
  (window as unknown as { game: typeof game }).game = game;
54
+
55
+ // The overlay comes down LAST, after any wiring of your own. There is none in
56
+ // this template — when you add some, put it above this line and wrap it:
57
+ //
58
+ // try { …your wiring… } catch (e) { showBootFailure(e); throw e; }
59
+ //
60
+ // A throw between the overlay coming down and the handle going up used to leave
61
+ // a level that renders perfectly with no player and no error of any kind.
62
+ document.querySelector('#loading')?.remove();