incanto 0.71.0 → 0.73.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 (92) hide show
  1. package/bin/incanto-check.mjs +114 -42
  2. package/bin/incanto-editor.mjs +15 -9
  3. package/bin/incanto-feel.mjs +11 -1
  4. package/bin/incanto-play.mjs +11 -1
  5. package/bin/incanto-playtest.mjs +11 -1
  6. package/bin/incanto-verify.mjs +9 -2
  7. package/dist/2d.d.ts +29 -4
  8. package/dist/2d.js +3 -3
  9. package/dist/3d.d.ts +137 -15
  10. package/dist/3d.js +6 -6
  11. package/dist/{agent8-Cfmd3ar_.js → agent8-CHTT4unP.js} +1 -1
  12. package/dist/{audio-player-L8yccdMP.d.ts → audio-player-BOrk4eQx.d.ts} +1 -1
  13. package/dist/{behavior-Dcz0fr1S.d.ts → behavior-J1cmVah0.d.ts} +9 -1
  14. package/dist/{create-game-LCHBLfA4.js → create-game-CAu-ucHg.js} +8 -7
  15. package/dist/{create-game-CH4kt78v.js → create-game-CbTLFjis.js} +37 -13
  16. package/dist/debug.d.ts +1 -1
  17. package/dist/debug.js +1 -1
  18. package/dist/editor.js +1036 -930
  19. package/dist/{environment-presets-99BzP_L-.js → environment-presets-BsFJM3v0.js} +277 -60
  20. package/dist/{gameplay-CNULJvwh.js → gameplay-CRte0OVf.js} +589 -35
  21. package/dist/gameplay.d.ts +136 -4
  22. package/dist/gameplay.js +2 -2
  23. package/dist/index.d.ts +6 -4
  24. package/dist/index.js +6 -6
  25. package/dist/{loader-8-IHvbKD.d.ts → loader-BAeWMYfF.d.ts} +10 -3
  26. package/dist/net.d.ts +2 -2
  27. package/dist/net.js +2 -2
  28. package/dist/{physics-2d-FhrXUc6B.js → physics-2d-CovokK7s.js} +94 -11
  29. package/dist/{physics-3d-CFEGxBXZ.js → physics-3d-BiK6Emwn.js} +202 -15
  30. package/dist/{picking-DVo7fI13.js → picking-Dtd8JInh.js} +2 -2
  31. package/dist/react.d.ts +1 -1
  32. package/dist/react.js +1 -1
  33. package/dist/{register-BYQCBySi.js → register-CY9QCCZs.js} +45 -9
  34. package/dist/{register-DuVdzxbq.js → register-CjociOtt.js} +19 -4
  35. package/dist/{replay-DEvp3kyV.js → replay-B6BbgGM_.js} +55 -12
  36. package/dist/{replay-F7IZHdFR.d.ts → replay-wZK5Ok5c.d.ts} +2 -2
  37. package/dist/{save-slots-Bvuh2p_r.js → save-slots-CEUGeLuB.js} +57 -3
  38. package/dist/{split-screen-eULetcg-.js → split-screen-BxZ5rBe7.js} +4 -4
  39. package/dist/{split-screen-CIYf1zSf.d.ts → split-screen-D6sx8z3Z.d.ts} +2 -2
  40. package/dist/{sprite-animation-CqR2o3SA.js → sprite-animation-Bz3DHD_4.js} +1 -1
  41. package/dist/{src-_jk0qLsS.js → src-D-dnVrFY.js} +1 -1
  42. package/dist/{test-CmN54kWv.js → test-DZmCFz0Q.js} +162 -30
  43. package/dist/test.d.ts +56 -5
  44. package/dist/test.js +2 -2
  45. package/dist/{touch-BnCyPA0G.js → touch-CioTZB-y.js} +1 -1
  46. package/dist/vite.d.ts +8 -1
  47. package/dist/vite.js +22 -5
  48. package/editor/assets/{agent8-yLIEYHbd.js → agent8-GuZ5u5bi.js} +1 -1
  49. package/editor/assets/{debug-u31w_yhq.js → debug-BbxionO2.js} +1 -1
  50. package/editor/assets/{index-DK9xMGpW.js → index-CNlTzQbm.js} +92 -92
  51. package/editor/index.html +1 -1
  52. package/package.json +1 -1
  53. package/schemas/scene.schema.json +634 -10
  54. package/skills/incanto-3d-character.md +113 -5
  55. package/skills/incanto-assets.md +9 -3
  56. package/skills/incanto-behaviors-and-scripts.md +26 -2
  57. package/skills/incanto-building-2d-games.md +15 -0
  58. package/skills/incanto-building-3d-games.md +45 -0
  59. package/skills/incanto-editor.md +10 -1
  60. package/skills/incanto-environment.md +7 -2
  61. package/skills/incanto-game-feel.md +16 -11
  62. package/skills/incanto-gameplay-behaviors.md +174 -15
  63. package/skills/incanto-node-reference.md +122 -45
  64. package/skills/incanto-physics-and-input.md +67 -5
  65. package/skills/incanto-scene-json-authoring.md +37 -1
  66. package/skills/incanto-verifying-your-game.md +19 -2
  67. package/templates-app/beacon-isle-3d/PROJECT/Status.md +8 -0
  68. package/templates-app/beacon-isle-3d/PROJECT/Structure.md +3 -0
  69. package/templates-app/beacon-isle-3d/package.json +1 -1
  70. package/templates-app/beacon-isle-3d/src/game.scene.json +512 -184
  71. package/templates-app/beacon-isle-3d/verify.ts +144 -0
  72. package/templates-app/molehill-2d/package.json +1 -1
  73. package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
  74. package/templates-app/platformer-2d/PROJECT/Structure.md +3 -0
  75. package/templates-app/platformer-2d/package.json +1 -1
  76. package/templates-app/platformer-2d/src/game.scene.json +319 -93
  77. package/templates-app/platformer-2d/verify.ts +54 -0
  78. package/templates-app/star-survivor/package.json +1 -1
  79. package/templates-app/star-survivor/src/game.scene.json +18 -9
  80. package/templates-app/tps-3d/PROJECT/Context.md +1 -1
  81. package/templates-app/tps-3d/PROJECT/Status.md +40 -1
  82. package/templates-app/tps-3d/PROJECT/Structure.md +19 -0
  83. package/templates-app/tps-3d/package.json +1 -1
  84. package/templates-app/tps-3d/src/behaviors.ts +9 -0
  85. package/templates-app/tps-3d/src/cover.scene.json +26 -0
  86. package/templates-app/tps-3d/src/game.scene.json +379 -80
  87. package/templates-app/tps-3d/src/main.ts +14 -0
  88. package/templates-app/tps-3d/src/pillar.scene.json +25 -0
  89. package/templates-app/tps-3d/verify.ts +582 -3
  90. package/templates-app/village-quest-3d/package.json +1 -1
  91. package/templates-app/village-quest-3d/src/grove.scene.json +98 -46
  92. package/templates-app/village-quest-3d/src/village.scene.json +449 -223
@@ -103,7 +103,11 @@ Rules the engine enforces with **hard errors** (it never warns silently):
103
103
  On export, default-equal values are omitted automatically.
104
104
  3. Prop keys and value kinds are validated against the type's schema:
105
105
  unknown key → `UNKNOWN_PROP` (message lists valid keys); wrong JSON kind
106
- (e.g. string where the default is boolean) → `PROP_TYPE_MISMATCH`.
106
+ (e.g. string where the default is boolean) → `PROP_TYPE_MISMATCH`. A prop
107
+ whose default is `null` means AUTO — the engine decides — and validates the
108
+ other kinds it declares (`drape`/`collide`/`islandEdge`/`Chase.ground` take
109
+ a boolean, `snapToGround` a boolean or a lift in metres, `reflectivity` a
110
+ number); the editor offers the boolean ones as auto / on / off.
107
111
  A few props accept TWO kinds — `Flowers3D.density` takes a preset name or
108
112
  plants per m², `Water3D.underwater` takes `true`/`false` or a settings
109
113
  object — and `incanto-node-reference.md` names both in its Kind column
@@ -398,6 +402,37 @@ that do exist at the failing spot).
398
402
  - Current limitation: exporting expands instances into full trees (the `instance` reference is
399
403
  not preserved on export yet).
400
404
  - Cycles (`a` instances `b` instances `a`) and missing resolvers → `UNRESOLVED_INSTANCE`.
405
+ - A placement's props go in `overrides`. `props` on an `instance:` node is a
406
+ hard `BAD_FORMAT` error — it used to be accepted and read by nothing, so a
407
+ position written there was silently the sub-scene's own.
408
+
409
+ ### Giving the loader the sub-scenes (the half that is not JSON)
410
+
411
+ `loadScene` never reads files: it asks `resolveScene(path)` for the JSON behind
412
+ an `instance:` string, synchronously, and without one a scene with a prefab in
413
+ it does not load. Every CLI (`incanto-check`, `-playtest`, `-verify`, `-feel`,
414
+ `-play`) passes one already, resolved against the SCENE's own folder — your
415
+ game and your harness are the two places you write it yourself:
416
+
417
+ ```ts
418
+ // main.ts — vite. Every *.scene.json beside this file, keyed by the path an
419
+ // `instance:` names.
420
+ const prefabs = import.meta.glob('./*.scene.json', { eager: true, import: 'default' });
421
+ const resolveScene = (path: string): unknown => prefabs[`./${path}`] ?? null;
422
+ await createGame2D({ canvas, scene: sceneJson, resolveScene });
423
+ ```
424
+
425
+ ```ts
426
+ // verify.ts — bun, no bundler: import the prefab and hand it over by path.
427
+ import crateJson from './src/crate.scene.json';
428
+ const resolveScene = (path: string) => (path === 'crate.scene.json' ? crateJson : null);
429
+ await runScript(sceneJson, { durationMs: 4000, resolveScene, steps: [...] });
430
+ ```
431
+
432
+ `examples/tiles-2d` is the worked example in 2D: two crates that ARE
433
+ `crate.scene.json`, one of them adding a rope child of its own. `examples/tps-3d`
434
+ is the 3D one: the arena's cover blocks and pillars are `cover.scene.json` and
435
+ `pillar.scene.json`, placed with a `position` override each.
401
436
 
402
437
  ## Error codes you will see (all hard failures at load)
403
438
 
@@ -417,6 +452,7 @@ that do exist at the failing spot).
417
452
  | `UNKNOWN_SIGNAL` | connection (or emit/on) names a signal the from node never declares | use a declared signal, or declare it (`static signals` / `declareSignal`) |
418
453
  | `UNKNOWN_BEHAVIOR` | `script.name` not registered | `registerBehavior(name, Class)` before `loadScene` |
419
454
  | `UNRESOLVED_INSTANCE` | no resolver, unknown path, or instance cycle | provide/fix `resolveScene`, break the cycle |
455
+ | `WRONG_DIMENSION` | a `*3D` node in a 2D scene (or the reverse), or `createGame2D` given a 3D scene | use the matching node type / the matching `createGame*` |
420
456
  | `DUPLICATE_NODE_TYPE` | two classes registered under one type name | rename one type, or `{ replace: true }` for hot reload |
421
457
  | `DUPLICATE_BEHAVIOR` | two classes registered under one behavior name | rename one, or `{ replace: true }` for hot reload |
422
458
  | `TREE_VIOLATION` | invalid name, re-parenting without detach, cycles, double root | follow the rule in the message |
@@ -41,6 +41,10 @@ $ bunx incanto verify # finds your scene AND your behaviou
41
41
  passes what was measured — plays, draws not measured.
42
42
  next: nothing here is broken — a win that takes skill or a sequence is out of reach of random play. Judge it with a scripted run: `bun run verify`
43
43
  ```
44
+ `--runs N` gives the `plays` rung more seeds (default 8). Eight see a one-in-eight event
45
+ 64% of the time; `bun run sweep` asks the six shipped starters for sixteen, and a starter that
46
+ falls out of the world once in twelve runs is how the arena in tps-3d got its `Respawn`.
47
+
44
48
 
45
49
  ### `agrees` — do two clients hold the same values?
46
50
 
@@ -72,7 +76,10 @@ encodes so you do not have to remember them:
72
76
  warned about is printed under it with a `!` — `loads` runs `incanto-check`,
73
77
  and the ladder used to read only whether it passed and drop the warnings, so a
74
78
  scene the check describes as "It will render black" came back as
75
- `✓ loads — the scene is legal and its assets resolve`;
79
+ `✓ loads — the scene is legal and its assets resolve` (LOCAL art is looked for on
80
+ disk; REMOTE urls are asked with a HEAD request — a 404 drops the claim to
81
+ `the scene is legal`, and a host that cannot be reached is a `note:`, never a
82
+ failure);
76
83
  - an **unmeasured** rung (`?`) is not a failure. "No dev server" means the
77
84
  question was never asked; treating that as a broken game sends you editing a
78
85
  scene that is fine;
@@ -218,7 +225,7 @@ const result = await runScript(sceneJson, {
218
225
  durationMs: 3000,
219
226
  seed: 42, // same seed → identical run
220
227
  steps: [
221
- { atMs: 0, vector: ['move', 1, 0] }, // hold right
228
+ { atMs: 0, vector: ['move', 1, 0] }, // hold right (y is DOWN: forward is [0, -1])
222
229
  { atMs: 1000, press: 'jump' },
223
230
  { atMs: 1100, release: 'jump' },
224
231
  { atMs: 1500, label: 'jump apex reached',
@@ -252,6 +259,16 @@ captures; `result.logs` holds everything behaviors logged via `this.log`.
252
259
  Steps that never execute (atMs beyond the run) are reported as failures —
253
260
  an assert cannot "pass" by not running.
254
261
 
262
+ **A game that has ended does not advance.** `GameFlow` stops the clock
263
+ (`timeScale 0`) on a win or a loss, and a pause does the same; after that every
264
+ `ctx.engine.step()` is a no-op and every value you read is the last one before
265
+ it stopped. A harness that lost its player three times inside one `do:` then
266
+ measured `0.00` for everything after it. The report now names each `do:`/`assert:`
267
+ step that ran with the clock stopped (`! at 4000ms [measure apex]: the clock
268
+ was stopped …`, also `result.stalled`) — read that line before reading the
269
+ zeros. Measure before the game ends, or `restartScene` / read `Flow.state` in
270
+ the step.
271
+
255
272
  Note: `validateScene`/`runScript` register node types and your `behaviors`
256
273
  into the process-global registries (hot-replacing same names). In a test
257
274
  suite, isolate with `clearRegistry()`/`clearBehaviors()` between files if
@@ -36,3 +36,11 @@
36
36
 
37
37
  - Boss attack telegraphs (charge-up glow, ground slam particles).
38
38
  - A hurt/attack clip for shades once one lands in the catalog.
39
+
40
+ ## This round's surfaces, on the island (2026-09-04)
41
+
42
+ `Pad` (StaticBody3D, `restitution 1`, `snapToGround: 0.1`) with a dead `Ball` dropped on it,
43
+ and `Walker` (CharacterBody3D + `Chase` on a child, `slopeLimitDeg 50`, `stepHeight 0.5`) on
44
+ the west slope, `loseRange 25` so it never joins the quest. `verify.ts` measures the rebound
45
+ (2.4 m of 3), the chase up the slope (8.5 m of 10, +1.75 m) and that the walker stays on the
46
+ terrain (0.97 m over `heightAt`).
@@ -22,3 +22,6 @@ verify.ts audit + quest E2E + hunt + death/respawn + replay
22
22
  keeps lit wards; `IsleDirector.onReady` re-applies their glow.
23
23
  - The whole Terrain subtree is static EXCEPT Sea and Clouds (auditScene
24
24
  catches the freeze-the-water mistake if you regress this).
25
+
26
+ - `Pad`, `Ball`, `Walker` — the harness's fixtures for a trampoline and a ground chaser on the
27
+ heightfield.
@@ -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.71.0",
17
+ "incanto": "^0.73.0",
18
18
  "three": "^0.184.0"
19
19
  },
20
20
  "devDependencies": {