incanto 0.29.0 → 0.31.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.
- package/bin/incanto-editor.mjs +101 -28
- package/dist/2d.d.ts +28 -6
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +81 -7
- package/dist/3d.js +4 -4
- package/dist/{audit-C6rMyict.js → audit-C4kmDK0o.js} +16 -0
- package/dist/{behavior-BAc0erXF.d.ts → behavior-D_jMpFh8.d.ts} +117 -55
- package/dist/{create-game-CNKXGfpr.js → create-game-DqOjMBUS.js} +61 -48
- package/dist/{create-game-CbuLWorm.js → create-game-z5XaB1p5.js} +27 -15
- package/dist/debug-draw-BM3DsvtT.js +18 -0
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +8 -3
- package/dist/{duplicate-BgtFrFo4.js → duplicate-KRPtUtzl.js} +1 -1
- package/dist/{editor-switch-B0wB_DSr.d.ts → editor-switch-BJb-CWfA.d.ts} +12 -1
- package/dist/editor.js +1346 -1231
- package/dist/{register-C44aSduO.js → environment-presets--DigHNg4.js} +42 -11
- package/dist/{gameplay-L05WgWd1.js → gameplay-BftxM_It.js} +14 -5
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +6 -6
- package/dist/{loader-B242FF6N.d.ts → loader-BYBrqTxP.d.ts} +1 -1
- package/dist/{loader-BZqOKfI2.js → loader-BlaRQGaA.js} +482 -6
- package/dist/net.d.ts +1 -1
- package/dist/net.js +3 -3
- package/dist/{pathfinding-BwD974Ss.d.ts → pathfinding-BwhqPD3i.d.ts} +1 -1
- package/dist/{physics-2d-CCVTrKOd.js → physics-2d-D9wquBvK.js} +30 -4
- package/dist/{physics-3d-BZZLtwJu.js → physics-3d-CnPygVGo.js} +41 -5
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-MelqEdza.js → register-CUY284Is.js} +3 -3
- package/dist/{register-BTg0EM7s.js → register-Dzkd6-os.js} +56 -380
- package/dist/{register-DWcWq4QG.js → register-tkR_8tWg.js} +4 -4
- package/dist/{registry-BVJ2HbCn.js → registry-CJdGpT2V.js} +6 -2
- package/dist/{editor-switch-CAKlJMIY.js → teardown-ByzfDPyu.js} +83 -4
- package/dist/test.d.ts +2 -7
- package/dist/test.js +43 -14
- package/dist/vite.d.ts +87 -1
- package/dist/vite.js +262 -3
- package/editor/assets/{agent8-DEVkEa3d.js → agent8-o27_Y1xN.js} +1 -1
- package/editor/assets/{debug-zGAtpDF0.js → debug-DfcWX3uW.js} +3 -2
- package/editor/assets/index-C9fb5QcT.js +10696 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/skills/incanto-editor.md +61 -8
- package/skills/incanto-physics-and-input.md +15 -0
- package/skills/incanto-verifying-your-game.md +68 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/vite.config.ts +7 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/vite.config.ts +7 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/vite.config.ts +7 -0
- package/dist/debug-draw-CZmOYjL2.js +0 -13
- package/editor/assets/index-Bx4UtWYY.js +0 -10586
package/editor/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Incanto Scene Editor</title>
|
|
7
7
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect width='16' height='16' rx='3' fill='%236ee7dc'/><text x='8' y='12' text-anchor='middle' font-size='11' font-family='monospace' fill='%230e1018'>i</text></svg>" />
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-C9fb5QcT.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
package/skills/incanto-editor.md
CHANGED
|
@@ -18,9 +18,50 @@ bunx incanto-editor level.scene.json --output build/level.scene.json --port 5179
|
|
|
18
18
|
|
|
19
19
|
**Project mode** (no file argument — the usual way) scans the current directory for
|
|
20
20
|
`*.scene.json` (skipping node_modules/dist/hidden dirs): one scene auto-opens; several
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
open the scene browser. The page can only ever address `*.scene.json` files under the
|
|
22
|
+
launch directory.
|
|
23
|
+
|
|
24
|
+
### The scene browser (`scenes`)
|
|
25
|
+
|
|
26
|
+
The `scenes` button opens the project as a tree, not a list of paths:
|
|
27
|
+
|
|
28
|
+
- **Every `.json` in the project is listed** — a scene is JSON by definition, so
|
|
29
|
+
nothing else could be one — and each row says whether it IS a scene, read from
|
|
30
|
+
the file rather than guessed from its name. A scene declares itself:
|
|
31
|
+
`{"format": 1, "type": "scene", "name", "root"}`, the same four keys the loader
|
|
32
|
+
demands. Scene rows show `3d · 24 nodes`; anything else is dimmed and marked
|
|
33
|
+
`not a scene`, and opening it fails with the reason (`"type" must be "scene",
|
|
34
|
+
and this file has no "type"`). So a scene you saved as `level.json` is right
|
|
35
|
+
there and opens; `package.json` is right there and tells you why it will not.
|
|
36
|
+
(Non-scene contents never leave the server — only the reason does.)
|
|
37
|
+
- **Folders**, sorted, with a scene count each; a chain that holds nothing else
|
|
38
|
+
collapses into one row (`src / scenes`). Small projects open fully expanded.
|
|
39
|
+
- **The scene you are editing** is marked and revealed, and the cursor starts on it.
|
|
40
|
+
- **A filter box** — type any part of a path; matches show wherever they are hiding.
|
|
41
|
+
Keyboard from that box: `↑↓` move · `→` open a folder · `←` close it · `⏎` load ·
|
|
42
|
+
`Esc` close (backdrop and ✕ work too).
|
|
43
|
+
- Each row carries **when it was last written and how big it is**, which is usually
|
|
44
|
+
how you recognise the file you were just in.
|
|
45
|
+
- **create** makes a new scene at the path in the box — left empty it uses the
|
|
46
|
+
placeholder, which tracks the folder you are standing in, so a scene lands beside
|
|
47
|
+
its siblings rather than at the project root. Parent dirs are created.
|
|
48
|
+
- Loading another scene while you have unsaved EDITS asks first.
|
|
49
|
+
|
|
50
|
+
**The same browser opens inside a running game.** When the game's dev server serves
|
|
51
|
+
the project's scenes, `☰ debug ▸ ✎ edit this scene` gives you the whole project: the
|
|
52
|
+
editor opens on the scene the game is running, and `scenes` switches to any other one,
|
|
53
|
+
saves back to ITS file, and `play ▸ run as the game` boots whichever scene you loaded.
|
|
54
|
+
That needs one plugin in `vite.config.ts` (already there in every `incanto-new`
|
|
55
|
+
project):
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { incantoScenes } from 'incanto/vite';
|
|
59
|
+
export default defineConfig({ plugins: [incantoScenes()] });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Without it the `scenes` button is still there and says what to add — a missing
|
|
63
|
+
one-line plugin should be a sentence you can act on, not a button that quietly
|
|
64
|
+
is not there. The editor still edits the scene the game booted with meanwhile.
|
|
24
65
|
|
|
25
66
|
Opens a local page (default `http://127.0.0.1:5179/`) with three panes:
|
|
26
67
|
|
|
@@ -45,9 +86,16 @@ Opens a local page (default `http://127.0.0.1:5179/`) with three panes:
|
|
|
45
86
|
(dimension, gravity with real inputs, environment/input/assets/multiplayer).
|
|
46
87
|
- **Viewport with DIRECT MANIPULATION** — a mode toolbar (top left) + the
|
|
47
88
|
Unity/Godot keys: **W move · E rotate · R scale** (active mode highlighted).
|
|
48
|
-
A collider-visibility toggle sits beside the mode tools
|
|
49
|
-
|
|
50
|
-
|
|
89
|
+
A collider-visibility toggle sits beside the mode tools, and it shows the
|
|
90
|
+
colliders the ENGINE builds, not a drawing of the `collider` prop: it attaches
|
|
91
|
+
Rapier to the edit view with `simulate: false` and turns on the same
|
|
92
|
+
`debugDraw` the play view uses. So a mesh-fitted body, an InstancedMesh3D
|
|
93
|
+
scatter's hulls, a terrain and a character capsule all appear — none of them
|
|
94
|
+
are in the scene JSON — and rotation, scale and offset are wherever physics
|
|
95
|
+
actually puts them. Nothing is simulated: bodies are posed from the tree each
|
|
96
|
+
tick (an outline follows a gizmo drag) and the solver never runs, so the scene
|
|
97
|
+
does not fall over while you edit it. Persisted, and carried into play mode
|
|
98
|
+
unchanged.
|
|
51
99
|
Move: axis arrows (X red, Y green, Z blue in 3D) + center square for free
|
|
52
100
|
movement. Rotate: drag the ring(s) — one ring in 2D, three world-axis rings
|
|
53
101
|
in 3D — with a live degree readout at the cursor. Scale: the same arrows with
|
|
@@ -56,8 +104,13 @@ and carried into play mode as the engine's physics debugDraw.
|
|
|
56
104
|
SNAP** — rotations to 15°, positions to the grid (10 px in 2D, 0.5 u in 3D),
|
|
57
105
|
scales to 0.25 steps (the readout shows the snapped value).
|
|
58
106
|
2D additionally supports click-pick, body drag, wheel zoom-at-cursor,
|
|
59
|
-
right/middle/Shift-drag pan, Alt+wheel scale, and collider wireframes
|
|
60
|
-
|
|
107
|
+
right/middle/Shift-drag pan, Alt+wheel scale, and collider wireframes.
|
|
108
|
+
**`F` frames the SELECTED node** (its whole subtree; a light or empty node has
|
|
109
|
+
no bounds, so the camera goes to it at a readable distance) — and the whole
|
|
110
|
+
scene when nothing is selected, which is the Maya/Unity/Unreal meaning of the
|
|
111
|
+
key. Same as the ⌖ frame button, and as `frame in view` in the tree's
|
|
112
|
+
right-click menu. This is how you find a node you selected in the tree that is
|
|
113
|
+
nowhere near the camera; double-click in the tree stays RENAME. The add-node dropdown is grouped by
|
|
61
114
|
category (Core / 2D / 2D Physics / 3D / 3D Physics / Network, plus a trailing
|
|
62
115
|
Other catch-all so an unclaimed type can never vanish from the list). The
|
|
63
116
|
dropdown, inspector and in-editor docs are registry/schema-driven — newly
|
|
@@ -243,6 +243,21 @@ it, a map with terrain is a wall of grid lines and the shape you came to check i
|
|
|
243
243
|
somewhere inside it. The debug overlay's **Colliders** menu item cycles
|
|
244
244
|
off → all → selected over exactly these two fields.
|
|
245
245
|
|
|
246
|
+
### Colliders without a simulation
|
|
247
|
+
|
|
248
|
+
`enablePhysics3D(engine, { simulate: false })` (and the 2D twin) builds the world
|
|
249
|
+
and never advances it: the body set is kept in step with the tree, every body is
|
|
250
|
+
posed FROM the tree each tick and propagated to its colliders, and then it stops
|
|
251
|
+
— no solver, no collision events, no write-back into node props. `debugDraw`
|
|
252
|
+
works exactly as above.
|
|
253
|
+
|
|
254
|
+
This is how the scene editor shows colliders while you edit: the real shapes,
|
|
255
|
+
including the ones that are not in the scene JSON at all (a mesh-fitted body, an
|
|
256
|
+
InstancedMesh3D scatter's hulls, a terrain, a character capsule), sitting where
|
|
257
|
+
the tree says, without your scene falling over while you look at it. Use it for
|
|
258
|
+
any "show me the collision geometry" tool. Do NOT use it to freeze a running
|
|
259
|
+
game — that is `engine.timeScale = 0`, which keeps the world coherent.
|
|
260
|
+
|
|
246
261
|
## Placement rules
|
|
247
262
|
|
|
248
263
|
`CharacterController2D` MUST be a direct child of a `CharacterBody2D` — the
|
|
@@ -155,6 +155,74 @@ export default { plugins: [incantoScenes()] };
|
|
|
155
155
|
Invalid `*.scene.json` saves keep the last good scene running and surface the
|
|
156
156
|
IncantoError in the terminal AND as a browser overlay.
|
|
157
157
|
|
|
158
|
+
The same plugin serves this project's scenes to the editor, so the one you switch
|
|
159
|
+
into from the running game (`☰ debug ▸ ✎ edit this scene`) can open, create and save
|
|
160
|
+
ANY scene in the project — not just the one the game booted with. `incantoScenes({
|
|
161
|
+
root })` bounds that to a directory other than vite's; nothing outside it is readable
|
|
162
|
+
or writable, and none of it exists in a build (`configureServer`).
|
|
163
|
+
|
|
164
|
+
## 5b. What a green `incanto-check` now covers
|
|
165
|
+
|
|
166
|
+
`validateScene` / `incanto-check` hard-fail on all of these, so they never reach
|
|
167
|
+
a browser:
|
|
168
|
+
|
|
169
|
+
- **Every prop's type AND its enum values** — `"mesh": "crystal"` names what is
|
|
170
|
+
valid instead of printing `ok` and throwing at boot. All 31 enum props.
|
|
171
|
+
- **`input{}`** — a declaration's shape (`"keys": "Space"` instead of
|
|
172
|
+
`["Space"]`, an unknown `type`, a wrong `touch`). This used to be checked only
|
|
173
|
+
by `Engine.setScene`, i.e. never headlessly.
|
|
174
|
+
- **`assets{}`** — every entry an object with a non-empty `url`.
|
|
175
|
+
- **`environment.preset`** — resolved only inside Renderer3D before, so a typo
|
|
176
|
+
survived every check and died at boot.
|
|
177
|
+
|
|
178
|
+
And `auditScene` (the warnings `incanto-check` prints) gained the loudest
|
|
179
|
+
"why is my screen black" of all: **nothing lights this 3D scene** — no light
|
|
180
|
+
node, no `environment` sky/hdri/preset, no ambient intensity. Ambient defaults to
|
|
181
|
+
0, so such a scene renders nothing, throws nothing and logs nothing.
|
|
182
|
+
|
|
183
|
+
## 6c. Engine diagnostics you can actually read
|
|
184
|
+
|
|
185
|
+
Every internal warning the engine produces — a GLB that 404'd, a body with no
|
|
186
|
+
collider, a retarget that dropped bones, an exception swallowed inside a physics
|
|
187
|
+
trigger handler — used to go to `console.*` and nowhere else, which is the one
|
|
188
|
+
channel a headless tool cannot read. The symptom was always the same: the model
|
|
189
|
+
simply never appears, and `logs` comes back empty.
|
|
190
|
+
|
|
191
|
+
They now go to **`engine.log` as well as the console**, so:
|
|
192
|
+
|
|
193
|
+
- `runScript().logs` contains them, and `describe()` prints them under the
|
|
194
|
+
failures (`! warn: …`).
|
|
195
|
+
- The debug overlay's **Logs** panel shows them live.
|
|
196
|
+
- `game.assetErrors()` lists every asset that failed **with its reason and ref**
|
|
197
|
+
— the direct answer to "why is my model not there". The store itself is
|
|
198
|
+
reachable as `renderer.assets` in both dimensions.
|
|
199
|
+
|
|
200
|
+
So the after-every-edit check is: `ok`, then **`stats().errors`**, then
|
|
201
|
+
**`assetErrors()`**.
|
|
202
|
+
|
|
203
|
+
## 6b. A thrown error no longer stops the game
|
|
204
|
+
|
|
205
|
+
One exception used to end everything: `requestAnimationFrame` reschedules AFTER
|
|
206
|
+
your callback returns, so a throw in any behavior's `update` killed the loop
|
|
207
|
+
permanently — no message, `stats().running` still `true`, a game that just
|
|
208
|
+
stopped. It no longer can.
|
|
209
|
+
|
|
210
|
+
- The thing that threw is **reported once** (which node, which script, which
|
|
211
|
+
phase) to `engine.log` AND the console, then **skipped**. Its children and
|
|
212
|
+
every other node keep running.
|
|
213
|
+
- **Your SCRIPT and the engine's NODE are skipped separately.** A typo in a
|
|
214
|
+
behavior attached to a `CharacterController3D` stops that behavior — the
|
|
215
|
+
character still walks and the camera still turns. Only a throw from the node's
|
|
216
|
+
own update quarantines the node.
|
|
217
|
+
- `engine.stats().errors` counts everything swallowed to stay alive. **A game
|
|
218
|
+
that looks fine with `errors: 3` is a broken game** — read `engine.log`.
|
|
219
|
+
- `engine.erroredNodes()` lists them; `engine.resumeErroredNodes()` puts them
|
|
220
|
+
back after you fix the code.
|
|
221
|
+
- `runScript()` FAILS the run when the count is non-zero. "It finished" must not
|
|
222
|
+
mean "nothing broke" — that is right for a player and wrong for a harness.
|
|
223
|
+
|
|
224
|
+
So the check after every edit is still `ok`, plus: **read `stats().errors`**.
|
|
225
|
+
|
|
158
226
|
## 7. See inside the RUNNING game (debug overlay)
|
|
159
227
|
|
|
160
228
|
```ts
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { incantoLibrary, incantoScenes } from 'incanto/vite';
|
|
1
2
|
import { defineConfig } from 'vite';
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
4
5
|
base: './',
|
|
6
|
+
// Dev-server only, and both are why the editor is useful here:
|
|
7
|
+
// - incantoScenes(): validates every *.scene.json the moment you save it,
|
|
8
|
+
// AND serves this project's scenes, so the editor (☰ debug ▸ edit this
|
|
9
|
+
// scene ▸ scenes) can open, create and save any scene in the project.
|
|
10
|
+
// - incantoLibrary(): the agent8 asset catalog behind the 📚 buttons.
|
|
11
|
+
plugins: [incantoScenes(), incantoLibrary()],
|
|
5
12
|
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { incantoLibrary, incantoScenes } from 'incanto/vite';
|
|
1
2
|
import { defineConfig } from 'vite';
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
4
5
|
base: './',
|
|
6
|
+
// Dev-server only, and both are why the editor is useful here:
|
|
7
|
+
// - incantoScenes(): validates every *.scene.json the moment you save it,
|
|
8
|
+
// AND serves this project's scenes, so the editor (☰ debug ▸ edit this
|
|
9
|
+
// scene ▸ scenes) can open, create and save any scene in the project.
|
|
10
|
+
// - incantoLibrary(): the agent8 asset catalog behind the 📚 buttons.
|
|
11
|
+
plugins: [incantoScenes(), incantoLibrary()],
|
|
5
12
|
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { incantoLibrary, incantoScenes } from 'incanto/vite';
|
|
1
2
|
import { defineConfig } from 'vite';
|
|
2
3
|
|
|
3
4
|
export default defineConfig({
|
|
4
5
|
base: './',
|
|
6
|
+
// Dev-server only, and both are why the editor is useful here:
|
|
7
|
+
// - incantoScenes(): validates every *.scene.json the moment you save it,
|
|
8
|
+
// AND serves this project's scenes, so the editor (☰ debug ▸ edit this
|
|
9
|
+
// scene ▸ scenes) can open, create and save any scene in the project.
|
|
10
|
+
// - incantoLibrary(): the agent8 asset catalog behind the 📚 buttons.
|
|
11
|
+
plugins: [incantoScenes(), incantoLibrary()],
|
|
5
12
|
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
//#region src/core/debug-draw.ts
|
|
2
|
-
const sources = /* @__PURE__ */ new Set();
|
|
3
|
-
/** @internal physics runtimes self-register on enable. */
|
|
4
|
-
function registerDebugSource(source) {
|
|
5
|
-
sources.add(source);
|
|
6
|
-
return () => sources.delete(source);
|
|
7
|
-
}
|
|
8
|
-
/** @internal renderers pull their dimension's sources. */
|
|
9
|
-
function debugSources(dimension) {
|
|
10
|
-
return [...sources].filter((s) => s.dimension === dimension);
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
export { registerDebugSource as n, debugSources as t };
|