incanto 0.54.0 → 0.55.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-BYfiwbQx.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-BfqmvXYD.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.54.0",
3
+ "version": "0.55.0",
4
4
  "description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
5
5
  "keywords": [
6
6
  "game-engine",
@@ -262,6 +262,9 @@
262
262
  {
263
263
  "$ref": "#/$defs/Label"
264
264
  },
265
+ {
266
+ "$ref": "#/$defs/Label3D"
267
+ },
265
268
  {
266
269
  "$ref": "#/$defs/LoftMesh3D"
267
270
  },
@@ -3337,6 +3340,180 @@
3337
3340
  },
3338
3341
  "required": ["name", "type"]
3339
3342
  },
3343
+ "Label3D": {
3344
+ "type": "object",
3345
+ "properties": {
3346
+ "name": {
3347
+ "type": "string"
3348
+ },
3349
+ "uid": {
3350
+ "type": "string"
3351
+ },
3352
+ "type": {
3353
+ "const": "Label3D"
3354
+ },
3355
+ "groups": {
3356
+ "type": "array",
3357
+ "items": {
3358
+ "type": "string"
3359
+ }
3360
+ },
3361
+ "tags": {
3362
+ "type": "object"
3363
+ },
3364
+ "props": {
3365
+ "type": "object",
3366
+ "properties": {
3367
+ "position": {
3368
+ "type": "array",
3369
+ "items": {
3370
+ "type": "number"
3371
+ },
3372
+ "minItems": 3,
3373
+ "maxItems": 3,
3374
+ "default": [0, 0, 0]
3375
+ },
3376
+ "rotation": {
3377
+ "type": "array",
3378
+ "items": {
3379
+ "type": "number"
3380
+ },
3381
+ "minItems": 3,
3382
+ "maxItems": 3,
3383
+ "default": [0, 0, 0]
3384
+ },
3385
+ "static": {
3386
+ "type": "boolean",
3387
+ "default": false
3388
+ },
3389
+ "scale": {
3390
+ "type": "array",
3391
+ "items": {
3392
+ "type": "number"
3393
+ },
3394
+ "minItems": 3,
3395
+ "maxItems": 3,
3396
+ "default": [1, 1, 1]
3397
+ },
3398
+ "visible": {
3399
+ "type": "boolean",
3400
+ "default": true
3401
+ },
3402
+ "renderOrder": {
3403
+ "type": "number",
3404
+ "default": 0
3405
+ },
3406
+ "orderGroup": {
3407
+ "type": "string",
3408
+ "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3409
+ "default": "default"
3410
+ },
3411
+ "snapToGround": {
3412
+ "default": null
3413
+ },
3414
+ "texture": {
3415
+ "type": "string",
3416
+ "default": ""
3417
+ },
3418
+ "size": {
3419
+ "type": "array",
3420
+ "items": {
3421
+ "type": "number"
3422
+ },
3423
+ "minItems": 2,
3424
+ "maxItems": 2,
3425
+ "default": [1, 1]
3426
+ },
3427
+ "billboard": {
3428
+ "type": "string",
3429
+ "enum": ["y", "full", "none"],
3430
+ "default": "full"
3431
+ },
3432
+ "anchor": {
3433
+ "type": "array",
3434
+ "items": {
3435
+ "type": "number"
3436
+ },
3437
+ "minItems": 2,
3438
+ "maxItems": 2,
3439
+ "default": [0.5, 0]
3440
+ },
3441
+ "tint": {
3442
+ "type": "string",
3443
+ "default": "#ffffff"
3444
+ },
3445
+ "opacity": {
3446
+ "type": "number",
3447
+ "default": 1
3448
+ },
3449
+ "flipX": {
3450
+ "type": "boolean",
3451
+ "default": false
3452
+ },
3453
+ "pixelArt": {
3454
+ "type": "boolean",
3455
+ "default": true
3456
+ },
3457
+ "alphaTest": {
3458
+ "type": "number",
3459
+ "default": 0.5
3460
+ },
3461
+ "castShadow": {
3462
+ "type": "boolean",
3463
+ "default": false
3464
+ },
3465
+ "shadowMode": {
3466
+ "type": "string",
3467
+ "enum": ["silhouette", "blob"],
3468
+ "default": "silhouette"
3469
+ },
3470
+ "text": {
3471
+ "type": "string",
3472
+ "default": ""
3473
+ },
3474
+ "height": {
3475
+ "type": "number",
3476
+ "default": 0.3
3477
+ },
3478
+ "color": {
3479
+ "type": "string",
3480
+ "default": "#ffffff"
3481
+ },
3482
+ "font": {
3483
+ "type": "string",
3484
+ "default": "sans-serif"
3485
+ },
3486
+ "outline": {
3487
+ "type": "string",
3488
+ "default": "#000000"
3489
+ }
3490
+ },
3491
+ "additionalProperties": false
3492
+ },
3493
+ "script": {
3494
+ "type": "object",
3495
+ "properties": {
3496
+ "name": {
3497
+ "type": "string"
3498
+ },
3499
+ "props": {
3500
+ "type": "object"
3501
+ }
3502
+ },
3503
+ "required": ["name"]
3504
+ },
3505
+ "network": {
3506
+ "type": "object"
3507
+ },
3508
+ "children": {
3509
+ "type": "array",
3510
+ "items": {
3511
+ "$ref": "#/$defs/node"
3512
+ }
3513
+ }
3514
+ },
3515
+ "required": ["name", "type"]
3516
+ },
3340
3517
  "LoftMesh3D": {
3341
3518
  "type": "object",
3342
3519
  "properties": {
@@ -183,8 +183,31 @@ camera yaw.
183
183
  A transform container that orients itself toward the camera every rendered frame;
184
184
  **children inherit the rotation** through the scene graph. Hang world-space UI
185
185
  under it — HP bars, pickup markers, floating icons — instead of hand-rolling
186
- camera math in game code. (There is no 3D text node — a nameplate or damage
187
- number is a canvas-rendered texture on a child `Sprite3D`.)
186
+ camera math in game code.
187
+
188
+ ### `Label3D` — text standing in the world
189
+
190
+ A nameplate, a sign, a damage number:
191
+
192
+ ```json
193
+ { "name": "Name", "type": "Label3D",
194
+ "props": { "text": "Goblin", "height": 0.25, "position": [0, 2, 0] } }
195
+ ```
196
+
197
+ - **`height`** is the cap height in METRES, and the quad follows what the text
198
+ measures — a sign is as wide as its words.
199
+ - It **faces the camera** by default (`billboard: "full"`): a damage number read
200
+ from behind is a bug. `"y"` keeps it upright for a nameplate over a character.
201
+ - **`outline`** is on by default, because white text over a bright wall is
202
+ unreadable and a damage number lands anywhere. `""` turns it off.
203
+ - It IS a `Sprite3D`, so `anchor`, `tint`, `opacity`, `alphaTest`, `renderOrder`
204
+ and `orderGroup` all work exactly as they do there.
205
+
206
+ A **damage number** is this node plus two lines: set `text`, then float it up
207
+ and fade `opacity` to 0 over ~0.6 s and `queueFree()`. Re-rasterising is
208
+ handled — the texture is rebuilt only when the text (or size/colour/font)
209
+ changes, and the old one is disposed, so a number per hit does not leak a
210
+ texture per hit.
188
211
 
189
212
  | Prop | Default | Notes |
190
213
  |---|---|---|
@@ -479,6 +479,35 @@ Signals: `movementStateChanged(state)`
479
479
  | `font` | `"monospace"` | string |
480
480
  | `align` | `"left"` | string |
481
481
 
482
+ ## `Label3D` — `incanto`
483
+
484
+ | Prop | Default | Kind |
485
+ |---|---|---|
486
+ | `position` | `[0,0,0]` | array |
487
+ | `rotation` | `[0,0,0]` | array |
488
+ | `static` | `false` | boolean |
489
+ | `scale` | `[1,1,1]` | array |
490
+ | `visible` | `true` | boolean |
491
+ | `renderOrder` | `0` | number |
492
+ | `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
493
+ | `snapToGround` | `null` | null |
494
+ | `texture` | `""` | string |
495
+ | `size` | `[1,1]` | array |
496
+ | `billboard` | `"full"` | one of: `y` `full` `none` |
497
+ | `anchor` | `[0.5,0]` | array |
498
+ | `tint` | `"#ffffff"` | string |
499
+ | `opacity` | `1` | number |
500
+ | `flipX` | `false` | boolean |
501
+ | `pixelArt` | `true` | boolean |
502
+ | `alphaTest` | `0.5` | number |
503
+ | `castShadow` | `false` | boolean |
504
+ | `shadowMode` | `"silhouette"` | one of: `silhouette` `blob` |
505
+ | `text` | `""` | string |
506
+ | `height` | `0.3` | number |
507
+ | `color` | `"#ffffff"` | string |
508
+ | `font` | `"sans-serif"` | string |
509
+ | `outline` | `"#000000"` | string |
510
+
482
511
  ## `LoftMesh3D` — `incanto/3d`
483
512
 
484
513
  | Prop | Default | Kind |
@@ -33,6 +33,10 @@ slices say which part of the frame to look at:
33
33
  | `renderMs` | the renderer, reported by itself | quality tier, `renderScale`, draw calls, shadows |
34
34
  | `otherMs` | the frame MINUS the three above | GC, browser layout, your own rAF work. **Allocations show up here.** |
35
35
 
36
+ The debug overlay's stats chip shows the same four numbers live
37
+ (`phys · logic · draw · other`), so you do not have to call anything to see a
38
+ frame go wrong while you are playing.
39
+
36
40
  `otherMs` is the one worth knowing about. A frame drop that everyone reads as a
37
41
  GPU problem is often garbage collection, and it looks identical from the outside
38
42
  — this engine lost a day to exactly that. A big `otherMs` with small everything
@@ -32,6 +32,7 @@ failures — but `framing` and `assetErrors()` you have to ASK for.
32
32
  $ bunx incanto-verify # finds your scene
33
33
  ✓ loads — the scene is legal and its assets resolve
34
34
  ? plays — nothing declares a win — 8 runs played without error, and there was no end to reach
35
+ ✓ feels — 5 of 7 fired — silent: /Game/Boss/Roar, /Game/Boss/Boom
35
36
  ? draws — the dev server is running on :5173, but no page answered
36
37
 
37
38
  passes what was measured — plays, draws not measured.
@@ -49,6 +50,12 @@ encodes so you do not have to remember them:
49
50
  - a scene that declares **no win** is not a scene that cannot be won. A
50
51
  walkabout has no end, and that is reported as unmeasured, not failed.
51
52
 
53
+ `feels` is the sound-and-effects rung: it lists what the scene DECLARES against
54
+ what actually fired during the playtest. A game whose feedback is wired but
55
+ never triggered plays perfectly and feels dead, and every other rung calls it
56
+ healthy. Nothing firing at all is a failure; some nodes staying silent is
57
+ reported by name, because the bot may simply never have reached the boss.
58
+
52
59
  Exit 1 only when a rung actually failed. `--behaviors src/behaviors.ts` matters:
53
60
  without it your game logic is stubbed and only the structure is played.
54
61
 
@@ -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.54.0",
17
+ "incanto": "^0.55.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.54.0",
16
+ "incanto": "^0.55.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.54.0",
16
+ "incanto": "^0.55.0",
17
17
  "three": "^0.184.0"
18
18
  },
19
19
  "devDependencies": {