incanto 0.27.0 → 0.29.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 (58) hide show
  1. package/README.md +44 -0
  2. package/bin/incanto-editor.mjs +118 -1
  3. package/dist/2d.d.ts +38 -5
  4. package/dist/2d.js +3 -3
  5. package/dist/3d.d.ts +496 -150
  6. package/dist/3d.js +5 -5
  7. package/dist/{behavior-CPibUfnH.d.ts → behavior-BAc0erXF.d.ts} +21 -0
  8. package/dist/{create-game-DUAtTqID.js → create-game-CNKXGfpr.js} +270 -47
  9. package/dist/{create-game-C0bPoURs.js → create-game-CbuLWorm.js} +53 -14
  10. package/dist/debug.d.ts +51 -6
  11. package/dist/debug.js +242 -19
  12. package/dist/editor-switch-B0wB_DSr.d.ts +59 -0
  13. package/dist/editor-switch-CAKlJMIY.js +161 -0
  14. package/dist/editor.d.ts +49 -0
  15. package/dist/editor.js +8439 -0
  16. package/dist/{gameplay-Ddk13pQ6.js → gameplay-L05WgWd1.js} +220 -37
  17. package/dist/gameplay.d.ts +1 -1
  18. package/dist/gameplay.js +1 -1
  19. package/dist/index.d.ts +22 -3
  20. package/dist/index.js +2 -2
  21. package/dist/{loader-DILt9PGC.d.ts → loader-B242FF6N.d.ts} +1 -1
  22. package/dist/net.d.ts +1 -1
  23. package/dist/net.js +2 -2
  24. package/dist/{pathfinding-RWYkNKx9.d.ts → pathfinding-BwD974Ss.d.ts} +1 -1
  25. package/dist/{physics-2d-DiVFFlH3.js → physics-2d-CCVTrKOd.js} +62 -2
  26. package/dist/{physics-3d-4mGzOZ2J.js → physics-3d-BZZLtwJu.js} +439 -8
  27. package/dist/react.d.ts +1 -1
  28. package/dist/react.js +1 -1
  29. package/dist/{register-nObreUQR.js → register-BTg0EM7s.js} +35 -3
  30. package/dist/{register-DcHXS1MA.js → register-C44aSduO.js} +5694 -5108
  31. package/dist/{register-CvpSUU3O.js → register-DWcWq4QG.js} +22 -2
  32. package/dist/{register-BFFE1Mh1.js → register-MelqEdza.js} +1 -1
  33. package/dist/test.d.ts +35 -3
  34. package/dist/test.js +104 -10
  35. package/dist/vite.d.ts +53 -1
  36. package/dist/vite.js +94 -2
  37. package/editor/assets/{agent8-DElIPozC.js → agent8-DEVkEa3d.js} +1 -1
  38. package/editor/assets/debug-zGAtpDF0.js +2 -0
  39. package/editor/assets/index-Bx4UtWYY.js +10586 -0
  40. package/editor/index.html +3 -157
  41. package/package.json +3 -2
  42. package/schemas/scene.schema.json +110 -4
  43. package/skills/incanto-3d-models.md +38 -0
  44. package/skills/incanto-assets.md +13 -0
  45. package/skills/incanto-building-3d-games.md +83 -6
  46. package/skills/incanto-editor.md +151 -0
  47. package/skills/incanto-environment.md +88 -1
  48. package/skills/incanto-node-reference.md +35 -1
  49. package/skills/incanto-physics-and-input.md +45 -6
  50. package/skills/incanto-verifying-your-game.md +51 -2
  51. package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +5 -0
  52. package/templates-app/beacon-isle-3d/package.json +1 -1
  53. package/templates-app/tps-3d/docs/project-3d-rules.md +5 -0
  54. package/templates-app/tps-3d/package.json +1 -1
  55. package/templates-app/village-quest-3d/docs/project-3d-rules.md +5 -0
  56. package/templates-app/village-quest-3d/package.json +1 -1
  57. package/editor/assets/index-BrneVqN0.js +0 -8330
  58. package/editor/assets/index-D8QvwvOm.css +0 -1
@@ -30,11 +30,43 @@ independent; enable the one matching your scene.
30
30
 
31
31
  2D collider shapes: `{"shape":"rect","size":[w,h]}` · `{"shape":"circle","radius":r}` ·
32
32
  `{"shape":"capsule","radius":r,"height":h}`.
33
- 3D: `{"shape":"box","size":[x,y,z]}` · `{"shape":"sphere","radius":r}` · `{"shape":"capsule",...}` ·
34
- `{"shape":"trimesh","vertices":[...],"indices":[...]}` · `{"shape":"heightfield"}` (STATIC-only;
35
- reads the grid from a `Terrain3D` child — see the incanto-environment skill).
33
+ 3D: `{"shape":"auto"}` · `{"shape":"box","size":[x,y,z]}` · `{"shape":"sphere","radius":r}` ·
34
+ `{"shape":"capsule",...}` · `{"shape":"trimesh","vertices":[...],"indices":[...]}` ·
35
+ `{"shape":"heightfield"}` (STATIC-only; reads the grid from a `Terrain3D` child — see the
36
+ incanto-environment skill).
36
37
  Malformed colliders are hard `BAD_FORMAT` errors at enable time.
37
38
 
39
+ **`{"shape":"auto"}` is the one to reach for on props.** It shapes the collider like the
40
+ `MeshInstance3D` the body CARRIES — box→cuboid, sphere→ball, cylinder/capsule→their own
41
+ shapes, `gem`→a convex hull of its real vertices — so a blocker can never disagree with what
42
+ the player sees. Hand-typed extents drift: a box "around" a bridge ends up wider than the
43
+ bridge and you stop in mid-air; a sphere "for" a stone ends up inside it and you clip through
44
+ the corners. Give the body its mesh as a CHILD and let the shape follow:
45
+
46
+ ```json
47
+ { "name": "DeckBody", "type": "StaticBody3D",
48
+ "props": { "position": [0, 3.2, -8], "rotation": [0, 34, 0], "collider": { "shape": "auto" } },
49
+ "children": [ { "name": "Deck", "type": "MeshInstance3D",
50
+ "props": { "mesh": "box", "size": [14, 0.22, 2.2] } } ] }
51
+ ```
52
+
53
+ Bodies ignore an ANCESTOR's rotation, so a yawed structure puts each body at top level with
54
+ its own `rotation` — the child mesh then turns with it, visual and collider together.
55
+
56
+ **`auto` works on a `ModelInstance3D` (GLB/glTF/VRM) too** — the shape comes from the model's
57
+ real triangles, baked through their own transforms, so an offset or `targetHeight`-fitted model
58
+ collides where it is DRAWN:
59
+
60
+ - on a **static** body (`StaticBody3D`, `Area3D`) → a triangle mesh: the model keeps its holes,
61
+ so you walk THROUGH an archway instead of into it. Level art can be dense; a collider over
62
+ ~20k triangles logs a note suggesting a low-poly collision model.
63
+ - on a **moving** body (`RigidBody3D`, `CharacterBody3D`) → the convex hull. Rapier's triangle
64
+ meshes are hollow shells; a dynamic one falls through the world.
65
+
66
+ The body simply does not exist until the model has downloaded — nothing is invented in the
67
+ meantime — and it appears the step the asset lands. A body is ONE shape, so `auto` fits one
68
+ mesh or one model and warns when the body carries more.
69
+
38
70
  - **`StaticBody2D/3D`** — immovable (ground, walls). Props: `collider`.
39
71
  - **`RigidBody2D/3D`** — simulated. Props: `collider`, `mass 1`, `gravityScale 1`,
40
72
  `fixedRotation false`, `friction 0.5`, `restitution 0`, `linearVelocity` (write to launch,
@@ -200,9 +232,16 @@ change scan was removed for performance).
200
232
  ## Debug drawing
201
233
 
202
234
  `physics.debugDraw = true` (the instance `enablePhysics2D/3D` returns) renders
203
- every collider as light-green wireframe lines IN THE GAME VIEW — Rapier's own
204
- debug geometry, so what you see is exactly what the solver sees. Default OFF;
205
- toggle it live whenever physics feels wrong.
235
+ every collider as light-green wireframe lines IN THE GAME VIEW — the shape data
236
+ the solver holds, so what you see is what it collides with. Default OFF; toggle
237
+ it live whenever physics feels wrong.
238
+
239
+ `physics.debugScope = node` narrows those lines to ONE node: its own colliders,
240
+ its descendants', or the nearest body above it when it owns none (so a visual
241
+ mesh child shows the body it belongs to). Null again for the whole world. Without
242
+ it, a map with terrain is a wall of grid lines and the shape you came to check is
243
+ somewhere inside it. The debug overlay's **Colliders** menu item cycles
244
+ off → all → selected over exactly these two fields.
206
245
 
207
246
  ## Placement rules
208
247
 
@@ -168,12 +168,61 @@ VITE_INCANTO_DEBUG=1 bun run dev # overlay on; plain `bun run dev` / prod buil
168
168
  A ☰ debug menu (top-left) toggles three draggable/resizable panels over the
169
169
  live game: **Explorer** (the scene tree — click any node), **Inspector** (the
170
170
  selected node's current state; numbers/strings/booleans/vectors editable
171
- in-place), **Logs** (an `engine.log` tail with level filters and an optional
171
+ in-place, and an OBJECT prop like `collider` opens into a row per key with the
172
+ `shape` as a dropdown — picking a shape writes a complete valid collider, never
173
+ a box's `size` under a sphere's tag; bulky values like a 54-row `transforms`
174
+ fold behind `▸ Array(54)` and expand on click, one row per element), **Logs** (an `engine.log` tail with level filters and an optional
172
175
  browser-console capture toggle) — plus **Stats**, an always-on-top chip pinned
173
176
  top-right (`60 fps · 12.1 ms` / `nodes 34 · tris 18.2k · calls 21`, refreshed
174
- ~2×/s; the same numbers any code can read via `game.stats()`). Manual boots:
177
+ ~2×/s; the same numbers any code can read via `game.stats()`) and
178
+ **Colliders**, a switch that draws every physics shape as light-green wireframe
179
+ in the game view. Manual boots:
175
180
  `(await import('incanto/debug')).attachDebugOverlay(engine)`.
176
181
 
182
+ The Inspector HOLDS STILL while you use it: it stops refreshing whenever an
183
+ input has focus or the pointer is inside the panel, and it keeps your scroll
184
+ position across refreshes. Live values resume the moment you move away.
185
+
186
+ **Colliders is the answer to "why did I stop in mid-air / fall through the
187
+ floor".** What you see is the shape data the solver holds — put it next to the
188
+ art and a collider that disagrees with its mesh is obvious in one glance.
189
+
190
+ One click cycles **off → all → selected** (the menu stays open while you cycle —
191
+ the item's label shows the state you landed on):
192
+
193
+ - `all` is every collider in the world. On a real map that means a terrain
194
+ heightfield's grid over everything, which is why the third state exists.
195
+ - `selected` draws only what the Explorer has picked: that node's colliders, its
196
+ descendants', or — if it owns none — the nearest BODY above it, so clicking a
197
+ visual `MeshInstance3D` shows the collider it hangs under rather than nothing.
198
+ A scatter field gives you all of its rows.
199
+
200
+ From code: `physics.debugDraw = true` and `physics.debugScope = node` (null for
201
+ everything).
202
+
203
+ **✎ edit this scene** is the last item in that menu, and it is the fastest loop
204
+ in the engine: the page you are playing in BECOMES the scene editor, from the
205
+ camera you were standing at — no reload, no second tab. Drag a boulder out of
206
+ the path, then **▶ play ▸ ⤢ run as the game** and the page is the game again,
207
+ running your edit. `game.openEditor()` is the same switch from code.
208
+
209
+ It follows `debug` (so a build with the overlay has it) and loads lazily, so a
210
+ game that never opens it never downloads it. `editor: false` opts out;
211
+ `editor: { save }` adds the editor's save button, wired to your own writer:
212
+
213
+ ```ts
214
+ createGame3D({
215
+ ...,
216
+ debug: import.meta.env.VITE_INCANTO_DEBUG === '1',
217
+ editor: { save: (json) => fetch('/api/scene', { method: 'PUT', body: JSON.stringify(json) }) },
218
+ });
219
+ ```
220
+
221
+ What crosses the switch is the AUTHORED scene JSON, not the live tree — physics
222
+ has moved the live one, and "edit this scene" must not mean "edit wherever the
223
+ simulation happened to be". Unsaved edits survive the round trip both ways; a
224
+ page reload is what drops them.
225
+
177
226
  **Security — `debug` defaults to `false` and there is NO URL/query toggle**, so
178
227
  a DEPLOYED build can never be switched on by an end user (no more `?incanto_debug=1`).
179
228
  Enable it only from your own dev environment via the env-var gate above. The
@@ -35,4 +35,9 @@ YOU MUST follow these rules EXACTLY when vibe-coding on this Incanto template:
35
35
  11. ✅ VERIFY LIKE A USER: `bun run check` validates the scene, `bun run verify`
36
36
  proves the loop headlessly, then `bun run dev` and actually PLAY what you
37
37
  changed (move, shoot, clear a wave) before declaring it done.
38
+ 12. 🔍 X-RAY WHEN IT LOOKS WRONG: `VITE_INCANTO_DEBUG=1 bun run dev` adds a ☰
39
+ debug menu — Explorer/Inspector (click a node, see and edit its live props),
40
+ Logs, Stats (fps · tris · draw calls) and Colliders (every physics shape as
41
+ wireframe). Blocked in mid-air or falling through the floor is a Colliders
42
+ question; a mystery frame-rate is a Stats question. Never ship the flag on.
38
43
  </userRequest>
@@ -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.27.0",
17
+ "incanto": "^0.29.0",
18
18
  "three": "^0.184.0"
19
19
  },
20
20
  "devDependencies": {
@@ -35,4 +35,9 @@ YOU MUST follow these rules EXACTLY when vibe-coding on this Incanto template:
35
35
  11. ✅ VERIFY LIKE A USER: `bun run check` validates the scene, `bun run verify`
36
36
  proves the loop headlessly, then `bun run dev` and actually PLAY what you
37
37
  changed (move, shoot, clear a wave) before declaring it done.
38
+ 12. 🔍 X-RAY WHEN IT LOOKS WRONG: `VITE_INCANTO_DEBUG=1 bun run dev` adds a ☰
39
+ debug menu — Explorer/Inspector (click a node, see and edit its live props),
40
+ Logs, Stats (fps · tris · draw calls) and Colliders (every physics shape as
41
+ wireframe). Blocked in mid-air or falling through the floor is a Colliders
42
+ question; a mystery frame-rate is a Stats question. Never ship the flag on.
38
43
  </userRequest>
@@ -13,7 +13,7 @@
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.27.0",
16
+ "incanto": "^0.29.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {
@@ -35,4 +35,9 @@ YOU MUST follow these rules EXACTLY when vibe-coding on this Incanto template:
35
35
  11. ✅ VERIFY LIKE A USER: `bun run check` validates the scene, `bun run verify`
36
36
  proves the loop headlessly, then `bun run dev` and actually PLAY what you
37
37
  changed (move, shoot, clear a wave) before declaring it done.
38
+ 12. 🔍 X-RAY WHEN IT LOOKS WRONG: `VITE_INCANTO_DEBUG=1 bun run dev` adds a ☰
39
+ debug menu — Explorer/Inspector (click a node, see and edit its live props),
40
+ Logs, Stats (fps · tris · draw calls) and Colliders (every physics shape as
41
+ wireframe). Blocked in mid-air or falling through the floor is a Colliders
42
+ question; a mystery frame-rate is a Stats question. Never ship the flag on.
38
43
  </userRequest>
@@ -13,7 +13,7 @@
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.27.0",
16
+ "incanto": "^0.29.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {