incanto 0.41.0 → 0.43.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-feel.mjs +20 -1
- package/bin/incanto-frame.mjs +144 -0
- package/dist/2d.d.ts +2 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +76 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-TA8nySqb.d.ts → behavior-62q0HWBO.d.ts} +3 -1
- package/dist/{create-game-u7TDbvln.js → create-game-B3vBWgVD.js} +160 -6
- package/dist/{create-game-CZpENyin.js → create-game-DFRbG0Bj.js} +6 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{environment-presets-pGTHb_V4.js → environment-presets-Ds5kXLoF.js} +2 -2
- package/dist/{gameplay-By8mslMc.js → gameplay-BQOeAid6.js} +50 -0
- package/dist/gameplay.d.ts +30 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -167
- package/dist/{loader-CvSDKC3v.d.ts → loader-CeyU_bm1.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-_UlKUoox.d.ts → pathfinding-C49JSNNq.d.ts} +1 -1
- package/dist/{physics-2d-CEnZFcpM.js → physics-2d-BmgXBNDB.js} +1 -1
- package/dist/{physics-3d-CumBBvQo.js → physics-3d-CLPFv99o.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-DuTlY56W.js → register-BSXV8T9F.js} +3 -1
- package/dist/{register-DnycZ91Q.js → register-D651it1J.js} +1 -1
- package/dist/{register-MSZvnHkp.js → register-R2JTnIMw.js} +1 -1
- package/dist/{replay-DN-kG4va.d.ts → replay-CAphXMyM.d.ts} +1 -1
- package/dist/{replay-DcWg4LT5.js → replay-DilbZgQI.js} +1 -1
- package/dist/src-CwYxzZKl.js +166 -0
- package/dist/{teardown-CCtAMDLB.js → teardown-yePMOE1K.js} +32 -1
- package/dist/{test-B4kSwQzq.js → test-BMgiiD5i.js} +135 -12
- package/dist/test.d.ts +38 -4
- package/dist/test.js +3 -3
- package/dist/vite.d.ts +61 -1
- package/dist/vite.js +149 -2
- package/editor/assets/{agent8-DCHkff44.js → agent8-Cl3qFuBB.js} +1 -1
- package/editor/assets/{debug-uHHxqj0a.js → debug-u3yLCciO.js} +1 -1
- package/editor/assets/{index-i1mIkyMA.js → index-Dk2ZlO68.js} +60 -60
- package/editor/index.html +1 -1
- package/package.json +3 -2
- package/skills/incanto-3d-character.md +19 -0
- package/skills/incanto-audio.md +6 -2
- package/skills/incanto-gameplay-behaviors.md +27 -0
- package/skills/incanto-node-reference.md +2 -0
- package/skills/incanto-verifying-your-game.md +41 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +47 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +53 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +43 -0
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-Dk2ZlO68.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.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game-engine",
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"incanto-play": "bin/incanto-play.mjs",
|
|
98
98
|
"incanto-playtest": "bin/incanto-playtest.mjs",
|
|
99
99
|
"incanto-feel": "bin/incanto-feel.mjs",
|
|
100
|
-
"incanto-new": "bin/incanto-new.mjs"
|
|
100
|
+
"incanto-new": "bin/incanto-new.mjs",
|
|
101
|
+
"incanto-frame": "bin/incanto-frame.mjs"
|
|
101
102
|
}
|
|
102
103
|
}
|
|
@@ -269,6 +269,25 @@ button is held — a free-roaming cursor never spins the camera. Vertical look i
|
|
|
269
269
|
STANDARD (non-inverted): mouse UP looks up (in free view the camera swings down so
|
|
270
270
|
it looks up at the character against the sky), mouse DOWN looks down.
|
|
271
271
|
|
|
272
|
+
### Check it instead of reasoning about it
|
|
273
|
+
|
|
274
|
+
`bunx incanto-feel <scene.json>` now ends with the answer:
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
facing: /Game/Player/Skin faces its travel (dot 1.00)
|
|
278
|
+
facing: /Game/Husk/Skin RUNS BACKWARDS (dot -1.00) — the skin points away from
|
|
279
|
+
the direction of travel.
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
It drives the character, measures where it actually went, and dots that with the
|
|
283
|
+
skin's forward axis. **+1 is right, −1 is backwards**, and a declared
|
|
284
|
+
`skinYawOffset` is subtracted first — so a model whose art faces another way is
|
|
285
|
+
correctly configured, not a false alarm.
|
|
286
|
+
|
|
287
|
+
This cannot be an `auditScene` warning: a scene file has no velocity, and the bug
|
|
288
|
+
is a behavior writing a heading at runtime. `facingReport()` from `incanto/test`
|
|
289
|
+
is the same check for your own tests.
|
|
290
|
+
|
|
272
291
|
## First-person weapon viewmodel + the tracer-from-the-muzzle rule
|
|
273
292
|
|
|
274
293
|
A weapon VIEWMODEL is just a `MeshInstance3D`/group child of the **root** `Camera`
|
package/skills/incanto-audio.md
CHANGED
|
@@ -274,9 +274,13 @@ For **background music** you usually want ONE track at a time and the ability to
|
|
|
274
274
|
**crossfade** to another (exploration → boss, level A → level B). That's
|
|
275
275
|
`engine.music` — a single-track manager that streams a clip and ramps gains:
|
|
276
276
|
|
|
277
|
+
**The bundle ships SFX only** — twelve effects, no music track. A background
|
|
278
|
+
track is your game's own file (`public/audio/…`) or a URL; `incanto/assets/audio/…`
|
|
279
|
+
has nothing to loop.
|
|
280
|
+
|
|
277
281
|
```ts
|
|
278
|
-
// Loop a track (full volume, music bus)
|
|
279
|
-
engine.music.play('
|
|
282
|
+
// Loop a track (full volume, music bus) — YOUR file, from public/:
|
|
283
|
+
engine.music.play('/audio/theme.mp3');
|
|
280
284
|
|
|
281
285
|
// Options: { loop = true, fadeIn = 0 (seconds), bus = 'music' }
|
|
282
286
|
engine.music.play('intro.mp3', { loop: false, fadeIn: 2 });
|
|
@@ -797,6 +797,33 @@ flow.win('AREA CLEAR');
|
|
|
797
797
|
flow.pause(); flow.resume();
|
|
798
798
|
```
|
|
799
799
|
|
|
800
|
+
### A pause menu, without a script
|
|
801
|
+
|
|
802
|
+
`GameFlow` drives one for you. Declare a `pause` action, put a `UiPanel` named
|
|
803
|
+
`PauseMenu` in the HUD, and that is the whole feature:
|
|
804
|
+
|
|
805
|
+
```json
|
|
806
|
+
{ "input": { "pause": { "type": "button", "keys": ["Escape"] } },
|
|
807
|
+
"root": { "name": "Game", "type": "Node3D", "children": [
|
|
808
|
+
{ "name": "Flow", "type": "Node", "script": { "name": "GameFlow" } },
|
|
809
|
+
{ "name": "HUD", "type": "HudLayer", "children": [
|
|
810
|
+
{ "name": "PauseMenu", "type": "UiPanel", "props": { "anchor": "center" },
|
|
811
|
+
"children": [{ "name": "Title", "type": "UiText", "props": { "text": "Paused" } }] }
|
|
812
|
+
] }
|
|
813
|
+
] } }
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
The panel is hidden while playing and shown while paused — `GameFlow` owns its
|
|
817
|
+
`visible`, so do not set it yourself. `pauseAction` and `pausePanelPath` rename
|
|
818
|
+
either half; `pausePanelPath: ""` turns it off.
|
|
819
|
+
|
|
820
|
+
The pause key is polled in `update()`, which still runs at `timeScale 0` — a
|
|
821
|
+
menu that cannot be closed by the key that opened it is worse than no menu.
|
|
822
|
+
|
|
823
|
+
**Give the Flow its own node.** A node holds one behavior, and your root
|
|
824
|
+
probably already carries the game's director script.
|
|
825
|
+
|
|
826
|
+
|
|
800
827
|
Terminal states ignore further transitions; the restart action (or
|
|
801
828
|
`flow.restart()`) reloads the scene from its source JSON — fresh nodes,
|
|
802
829
|
physics, input. Listen to the `flowChanged(state)` signal for custom UI.
|
|
@@ -1324,8 +1324,10 @@ Signals: `dayPhaseChanged`
|
|
|
1324
1324
|
| Prop | Default | Kind |
|
|
1325
1325
|
|---|---|---|
|
|
1326
1326
|
| `restartAction` | `"restart"` | string |
|
|
1327
|
+
| `pauseAction` | `"pause"` | string |
|
|
1327
1328
|
| `freezeOnEnd` | `true` | boolean |
|
|
1328
1329
|
| `bannerPath` | `"%Banner"` | node path |
|
|
1330
|
+
| `pausePanelPath` | `"%PauseMenu"` | node path |
|
|
1329
1331
|
|
|
1330
1332
|
Signals: `flowChanged`
|
|
1331
1333
|
|
|
@@ -320,6 +320,47 @@ ceiling — drive `engine.timeScale`, with `0.25× 0.5× 1× 2×` presets:
|
|
|
320
320
|
number is refused and negatives clamp to 0: the scale multiplies every dt in
|
|
321
321
|
the engine, so one NaN would take physics, timers and animation with it.
|
|
322
322
|
|
|
323
|
+
### `bunx incanto-frame` — what is actually on screen
|
|
324
|
+
|
|
325
|
+
The rung above framing. `framing` PREDICTS what the camera should see from the
|
|
326
|
+
scene graph; this measures what the GPU drew — the only one that can catch a
|
|
327
|
+
black screen, a material that failed, or a shader drawing where it should not.
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
$ bunx incanto-frame
|
|
331
|
+
frame 1280×720 · luminance 0.62
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
$ bunx incanto-frame
|
|
336
|
+
BLACK SCREEN — nothing was drawn (no light, no camera, or nothing in view)
|
|
337
|
+
frame 1280×720 · luminance 0.00
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Start your game's dev server and open the page first: **the pixels are in the
|
|
341
|
+
browser, not in the dev server.** You do not have to tell it where anything is —
|
|
342
|
+
it reads the ports that are actually listening, asks each one whether it is an
|
|
343
|
+
incanto dev server, and asks that page for a frame over vite's own HMR channel.
|
|
344
|
+
|
|
345
|
+
It writes **no files**. `--json` gives the full report, including a 16×9 grid of
|
|
346
|
+
mean cell colours — enough to answer *where* the frame changed, small enough to
|
|
347
|
+
read. From game code or the console, `game.frame()` returns the same object.
|
|
348
|
+
|
|
349
|
+
Three outcomes, each with its own fix:
|
|
350
|
+
|
|
351
|
+
| | |
|
|
352
|
+
| --- | --- |
|
|
353
|
+
| `no incanto dev server found` | start the dev server |
|
|
354
|
+
| `running on :5173, but no page is connected` | open the preview |
|
|
355
|
+
| a report | read it |
|
|
356
|
+
|
|
357
|
+
Exit code 1 on a black screen, so CI can gate on it.
|
|
358
|
+
|
|
359
|
+
**What it cannot do:** a 16×9 grid does not see a one-pixel seam. It answers
|
|
360
|
+
"did anything render, and roughly what does it look like", not "is this frame
|
|
361
|
+
pixel-identical to last week's". For exact regression detection use the numbers
|
|
362
|
+
(`incanto-feel`, conformance baselines), which are diffable and do not flap.
|
|
363
|
+
|
|
323
364
|
The Inspector HOLDS STILL while you use it: it stops refreshing whenever an
|
|
324
365
|
input has focus or the pointer is inside the panel, and it keeps your scroll
|
|
325
366
|
position across refreshes. Live values resume the moment you move away.
|
|
@@ -67,6 +67,14 @@
|
|
|
67
67
|
"type": "button",
|
|
68
68
|
"keys": ["Mouse0", "KeyF"],
|
|
69
69
|
"touch": "button"
|
|
70
|
+
},
|
|
71
|
+
"pause": {
|
|
72
|
+
"type": "button",
|
|
73
|
+
"keys": ["Escape"]
|
|
74
|
+
},
|
|
75
|
+
"restart": {
|
|
76
|
+
"type": "button",
|
|
77
|
+
"keys": ["KeyR"]
|
|
70
78
|
}
|
|
71
79
|
},
|
|
72
80
|
"assets": {
|
|
@@ -106,6 +114,16 @@
|
|
|
106
114
|
"name": "IsleDirector"
|
|
107
115
|
},
|
|
108
116
|
"children": [
|
|
117
|
+
{
|
|
118
|
+
"name": "Flow",
|
|
119
|
+
"type": "Node",
|
|
120
|
+
"script": {
|
|
121
|
+
"name": "GameFlow",
|
|
122
|
+
"props": {
|
|
123
|
+
"pausePanelPath": "%PauseMenu"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
109
127
|
{
|
|
110
128
|
"name": "Terrain",
|
|
111
129
|
"type": "Node3D",
|
|
@@ -2946,6 +2964,35 @@
|
|
|
2946
2964
|
"anchor": "bottomRight",
|
|
2947
2965
|
"shadow": true
|
|
2948
2966
|
}
|
|
2967
|
+
},
|
|
2968
|
+
{
|
|
2969
|
+
"name": "PauseMenu",
|
|
2970
|
+
"type": "UiPanel",
|
|
2971
|
+
"props": {
|
|
2972
|
+
"anchor": "center",
|
|
2973
|
+
"layout": "column",
|
|
2974
|
+
"gap": 10,
|
|
2975
|
+
"padding": 18
|
|
2976
|
+
},
|
|
2977
|
+
"children": [
|
|
2978
|
+
{
|
|
2979
|
+
"name": "PausedTitle",
|
|
2980
|
+
"type": "UiText",
|
|
2981
|
+
"props": {
|
|
2982
|
+
"text": "Paused",
|
|
2983
|
+
"size": 24
|
|
2984
|
+
}
|
|
2985
|
+
},
|
|
2986
|
+
{
|
|
2987
|
+
"name": "ResumeHint",
|
|
2988
|
+
"type": "UiText",
|
|
2989
|
+
"props": {
|
|
2990
|
+
"text": "Esc to resume · R to restart",
|
|
2991
|
+
"size": 13,
|
|
2992
|
+
"color": "#c9d2dd"
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
]
|
|
2949
2996
|
}
|
|
2950
2997
|
]
|
|
2951
2998
|
}
|
|
@@ -54,6 +54,14 @@
|
|
|
54
54
|
"reload": {
|
|
55
55
|
"type": "button",
|
|
56
56
|
"keys": ["KeyR"]
|
|
57
|
+
},
|
|
58
|
+
"pause": {
|
|
59
|
+
"type": "button",
|
|
60
|
+
"keys": ["Escape"]
|
|
61
|
+
},
|
|
62
|
+
"restart": {
|
|
63
|
+
"type": "button",
|
|
64
|
+
"keys": ["KeyR"]
|
|
57
65
|
}
|
|
58
66
|
},
|
|
59
67
|
"assets": {
|
|
@@ -92,6 +100,16 @@
|
|
|
92
100
|
}
|
|
93
101
|
},
|
|
94
102
|
"children": [
|
|
103
|
+
{
|
|
104
|
+
"name": "Flow",
|
|
105
|
+
"type": "Node",
|
|
106
|
+
"script": {
|
|
107
|
+
"name": "GameFlow",
|
|
108
|
+
"props": {
|
|
109
|
+
"pausePanelPath": "%PauseMenu"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
95
113
|
{
|
|
96
114
|
"name": "Arena",
|
|
97
115
|
"type": "Node3D",
|
|
@@ -651,6 +669,41 @@
|
|
|
651
669
|
"script": {
|
|
652
670
|
"name": "HudUpdater"
|
|
653
671
|
}
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"name": "HUD",
|
|
675
|
+
"type": "HudLayer",
|
|
676
|
+
"children": [
|
|
677
|
+
{
|
|
678
|
+
"name": "PauseMenu",
|
|
679
|
+
"type": "UiPanel",
|
|
680
|
+
"props": {
|
|
681
|
+
"anchor": "center",
|
|
682
|
+
"layout": "column",
|
|
683
|
+
"gap": 10,
|
|
684
|
+
"padding": 18
|
|
685
|
+
},
|
|
686
|
+
"children": [
|
|
687
|
+
{
|
|
688
|
+
"name": "PausedTitle",
|
|
689
|
+
"type": "UiText",
|
|
690
|
+
"props": {
|
|
691
|
+
"text": "Paused",
|
|
692
|
+
"size": 24
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
"name": "ResumeHint",
|
|
697
|
+
"type": "UiText",
|
|
698
|
+
"props": {
|
|
699
|
+
"text": "Esc to resume · R to restart",
|
|
700
|
+
"size": 13,
|
|
701
|
+
"color": "#c9d2dd"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
]
|
|
654
707
|
}
|
|
655
708
|
]
|
|
656
709
|
},
|
|
@@ -67,6 +67,10 @@
|
|
|
67
67
|
"restart": {
|
|
68
68
|
"type": "button",
|
|
69
69
|
"keys": ["KeyR"]
|
|
70
|
+
},
|
|
71
|
+
"pause": {
|
|
72
|
+
"type": "button",
|
|
73
|
+
"keys": ["Escape"]
|
|
70
74
|
}
|
|
71
75
|
},
|
|
72
76
|
"assets": {
|
|
@@ -106,6 +110,16 @@
|
|
|
106
110
|
"name": "GroveDirector"
|
|
107
111
|
},
|
|
108
112
|
"children": [
|
|
113
|
+
{
|
|
114
|
+
"name": "Flow",
|
|
115
|
+
"type": "Node",
|
|
116
|
+
"script": {
|
|
117
|
+
"name": "GameFlow",
|
|
118
|
+
"props": {
|
|
119
|
+
"pausePanelPath": "%PauseMenu"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
109
123
|
{
|
|
110
124
|
"name": "Ground",
|
|
111
125
|
"type": "StaticBody3D",
|
|
@@ -792,6 +806,35 @@
|
|
|
792
806
|
"anchor": "bottomRight",
|
|
793
807
|
"shadow": true
|
|
794
808
|
}
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
"name": "PauseMenu",
|
|
812
|
+
"type": "UiPanel",
|
|
813
|
+
"props": {
|
|
814
|
+
"anchor": "center",
|
|
815
|
+
"layout": "column",
|
|
816
|
+
"gap": 10,
|
|
817
|
+
"padding": 18
|
|
818
|
+
},
|
|
819
|
+
"children": [
|
|
820
|
+
{
|
|
821
|
+
"name": "PausedTitle",
|
|
822
|
+
"type": "UiText",
|
|
823
|
+
"props": {
|
|
824
|
+
"text": "Paused",
|
|
825
|
+
"size": 24
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
"name": "ResumeHint",
|
|
830
|
+
"type": "UiText",
|
|
831
|
+
"props": {
|
|
832
|
+
"text": "Esc to resume · R to restart",
|
|
833
|
+
"size": 13,
|
|
834
|
+
"color": "#c9d2dd"
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
]
|
|
795
838
|
}
|
|
796
839
|
]
|
|
797
840
|
}
|