incanto 0.46.0 → 0.48.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/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-Y-93awAL.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-B-6eYZEi.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incanto",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
5
5
  "keywords": [
6
6
  "game-engine",
@@ -98,6 +98,8 @@
98
98
  "incanto-playtest": "bin/incanto-playtest.mjs",
99
99
  "incanto-feel": "bin/incanto-feel.mjs",
100
100
  "incanto-new": "bin/incanto-new.mjs",
101
- "incanto-frame": "bin/incanto-frame.mjs"
101
+ "incanto-frame": "bin/incanto-frame.mjs",
102
+ "incanto-verify": "./bin/incanto-verify.mjs",
103
+ "incanto-logs": "./bin/incanto-logs.mjs"
102
104
  }
103
105
  }
@@ -19,6 +19,7 @@ bunx incanto-model public/models/knight.glb
19
19
  # anim Idle: 2.4s
20
20
  # anim Run: 0.8s ← exact clip names for `animation`
21
21
  bunx incanto-model avatar.vrm --json # full machine-readable report
22
+ bunx incanto-model https://.../goblin.glb # a URL works anywhere a path does
22
23
  ```
23
24
 
24
25
  The report gives you: the TRANSFORMED scene bounding box (size/center/min/max — skinned
@@ -63,6 +64,35 @@ tint), `castShadow`/`receiveShadow`, plus the usual Node3D transform.
63
64
 
64
65
  ## Animating named sub-nodes (wheels, turrets, doors) — `poseNode`
65
66
 
67
+ ## What the file will DO here
68
+
69
+ `incanto-model` ends with a verdict, and it answers the three questions that
70
+ cost the most time. Finding an asset is the agent8 library's job — its search
71
+ matches meaning. This says whether what it found works in YOUR scene:
72
+
73
+ ```
74
+ mixamorig rig — the 3d/animations clips play on this as they are
75
+ stands 1.5 units tall
76
+ ```
77
+ ```
78
+ skinned, but NOT a mixamorig rig — the 3d/animations clips will not bind to it
79
+ (bones are matched by name; a mismatch keeps the bind pose and only warns)
80
+ stands 28.45 units tall — not a character's size; set targetHeight (1.7) to fix it
81
+ clips in the file: die, idle, walk, normal_attack, … (play by name, no asset needed)
82
+ ```
83
+ ```
84
+ does NOT stand on its own origin — it sits 10.1 units above the origin. A node at
85
+ [0,0,0] puts it there too; offset the node, or expect an empty-looking frame
86
+ ```
87
+ ```
88
+ an animation CLIP — no mesh of its own. It plays ON a character: declare it as
89
+ {"type":"animation"} and point a ModelInstance3D's `animation` at it. Used as a
90
+ `model` it draws nothing at all, with no error
91
+ ```
92
+
93
+ It then prints the scene JSON to paste — the asset entry and the node, with
94
+ `targetHeight` already set when the raw size calls for it.
95
+
66
96
  Many GLBs ship articulated parts as NAMED nodes (`bunx incanto-model <file>` lists them —
67
97
  e.g. the Kenney vehicles have `wheel-front-left` … `wheel-back-right`). From a behavior,
68
98
  rotate one per frame with `poseNode(name, [rxDeg, ryDeg, rzDeg])` (local Euler XYZ):
@@ -26,6 +26,34 @@ A run that finishes is not a run that worked. `runScript()` fails the run when
26
26
  `stats().errors` is non-zero, and prints the engine's warnings under the
27
27
  failures — but `framing` and `assetErrors()` you have to ASK for.
28
28
 
29
+ ## 0. The whole ladder, one command: `incanto-verify`
30
+
31
+ ```
32
+ $ bunx incanto-verify # finds your scene
33
+ ✓ loads — the scene is legal and its assets resolve
34
+ ? plays — nothing declares a win — 8 runs played without error, and there was no end to reach
35
+ ? draws — the dev server is running on :5173, but no page answered
36
+
37
+ passes what was measured — plays, draws not measured.
38
+ next: if it is meant to be finishable, emit `won` (GameFlow, ScoreKeeper, or your own behaviour)
39
+ ```
40
+
41
+ Runs the rungs below in order and says the ONE thing to do next. Three rules it
42
+ encodes so you do not have to remember them:
43
+
44
+ - a **failed** rung makes the ones above it meaningless, so only the first is
45
+ worth reading — the rest are marked `·` skipped;
46
+ - an **unmeasured** rung (`?`) is not a failure. "No dev server" means the
47
+ question was never asked; treating that as a broken game sends you editing a
48
+ scene that is fine;
49
+ - a scene that declares **no win** is not a scene that cannot be won. A
50
+ walkabout has no end, and that is reported as unmeasured, not failed.
51
+
52
+ Exit 1 only when a rung actually failed. `--behaviors src/behaviors.ts` matters:
53
+ without it your game logic is stubbed and only the structure is played.
54
+
55
+ The sections below are the same rungs one at a time, for when you need the detail.
56
+
29
57
  ## 1. After EVERY scene edit: `incanto-check`
30
58
 
31
59
  ```bash
@@ -320,6 +348,32 @@ ceiling — drive `engine.timeScale`, with `0.25× 0.5× 1× 2×` presets:
320
348
  number is refused and negatives clamp to 0: the scale multiplies every dt in
321
349
  the engine, so one NaN would take physics, timers and animation with it.
322
350
 
351
+ ### `bunx incanto-logs` — what the game is SAYING
352
+
353
+ `incanto-frame` gets the pixels out of the browser; this gets the words. The
354
+ engine writes diagnostics for exactly this — and until they had a channel out,
355
+ they reached a human only, in the debug overlay's logs panel.
356
+
357
+ ```
358
+ $ bunx incanto-logs
359
+ asset $characters/base never loaded: … responded with 404
360
+ [error] incanto: failed to load model '…/NO-SUCH-MODEL.glb'
361
+ 82 nodes · frame rate not measurable — the page is hidden (a window covered by
362
+ another counts), and the browser throttles it. Bring it to the front
363
+ ```
364
+
365
+ That game's grass, water and trees all rendered — `incanto-frame` called it
366
+ healthy (`subject fills 84.2%`) because they ARE there. Only the player was
367
+ missing. **Pixels and words answer different questions; a game can pass one and
368
+ fail the other**, which is why both are rungs.
369
+
370
+ It needs no render, so it answers from a page the browser has stopped drawing.
371
+ Exit 1 when something is wrong: an error logged, an error swallowed to keep the
372
+ game alive, or an asset that never loaded.
373
+
374
+ A repeated warning is folded into one line with a count (`×600`) — a game
375
+ shouting the same thing every frame has one problem, not six hundred.
376
+
323
377
  ### `bunx incanto-frame` — what is actually on screen
324
378
 
325
379
  The rung above framing. `framing` PREDICTS what the camera should see from the
@@ -329,6 +383,22 @@ black screen, a material that failed, or a shader drawing where it should not.
329
383
  ```
330
384
  $ bunx incanto-frame
331
385
  frame 1280×720 · luminance 0.62
386
+ subject 412×690 at 434,18 · fills 21.4% of frame
387
+ ```
388
+
389
+ `subject` is what the frame is OF: everything that is not the background,
390
+ measured from the frame's own edges. It answers the question `black` and
391
+ `uniform` cannot — **is the thing IN the shot, and can you see it**:
392
+
393
+ ```
394
+ nothing but background — the camera is pointed away from everything in the scene
395
+ ```
396
+ ```
397
+ the subject fills almost nothing (0.3%) — the camera is too far back, or what
398
+ you meant to see is not what got drawn
399
+ ```
400
+ ```
401
+ subject 1280×720 at 0,0 · fills 84.1% of frame · CLIPPED by the frame edge
332
402
  ```
333
403
 
334
404
  ```
@@ -342,7 +412,49 @@ browser, not in the dev server.** You do not have to tell it where anything is
342
412
  it reads the ports that are actually listening, asks each one whether it is an
343
413
  incanto dev server, and asks that page for a frame over vite's own HMR channel.
344
414
 
345
- It writes **no files**. `--json` gives the full report, including a 16×9 grid of
415
+ #### Drive it somewhere first
416
+
417
+ Every interesting state in a game is downstream of input, and the boot screen is
418
+ the only frame anything could capture before this:
419
+
420
+ ```
421
+ $ bunx incanto-frame --do "vector move 0 1; step 3000; vector move 0 0" --out bridge.png
422
+ frame 1280×720 · luminance 0.68
423
+ subject fills 21.4% of frame
424
+ drove 180 frames before capturing
425
+ wrote bridge.png — open it, or read it
426
+ ```
427
+
428
+ The same words `incanto-play` takes — `press`/`release ACTION`, `vector ACTION X Y`,
429
+ `key CODE down|up`, `pointer DX DY`, `step MS`, separated by semicolons or
430
+ newlines. `--do-file` reads a longer plan from a file. One vocabulary for the
431
+ headless gamepad and the live one.
432
+
433
+ `step` waits on the REAL clock: this is the running game, with its own loop, its
434
+ own physics and its own animation, and stepping it by hand would fight all three.
435
+
436
+ **`drove N frames` is the number to check.** A browser stops animating a tab it
437
+ considers hidden — including a window merely covered by another — and the inputs
438
+ then land on a game that never advances: the capture comes back UNCHANGED and
439
+ looks perfectly healthy. `drove 0 frames` is refused with an error rather than
440
+ handed over as a picture.
441
+
442
+ #### Look at it
443
+
444
+ ```
445
+ $ bunx incanto-frame --out shot.png
446
+ frame 1280×720 · luminance 0.62
447
+ subject 412×690 at 434,18 · fills 21.4% of frame
448
+ wrote shot.png — open it, or read it
449
+ ```
450
+
451
+ `--out` writes the frame as a PNG (`--size N` sets the longest side, default
452
+ 512). Read it like any other image. The numbers above are cheaper and are what
453
+ you should assert on, but when a report says a scene is fine and it plainly is
454
+ not, a picture settles it in one look — and there is still no browser to install
455
+ and nothing headless involved: the page that is already open does the drawing.
456
+
457
+ Without `--out` it writes **no files**. `--json` gives the full report, including a 16×9 grid of
346
458
  mean cell colours — enough to answer *where* the frame changed, small enough to
347
459
  read. From game code or the console, `game.frame()` returns the same object.
348
460
 
@@ -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.46.0",
17
+ "incanto": "^0.48.0",
18
18
  "three": "^0.184.0"
19
19
  },
20
20
  "devDependencies": {
@@ -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.46.0",
16
+ "incanto": "^0.48.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {
@@ -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.46.0",
16
+ "incanto": "^0.48.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {