incanto 0.12.0 → 0.14.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/README.md +22 -0
- package/bin/incanto-new.mjs +87 -0
- package/dist/2d.d.ts +2 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +219 -82
- package/dist/3d.js +74 -4
- package/dist/{behavior-Bod1AyJS.d.ts → behavior-CPibUfnH.d.ts} +4 -2
- package/dist/{create-game-C_xf4gm9.js → create-game-Ct86zczq.js} +5 -5
- package/dist/{create-game-B2fewJUy.js → create-game-OSntcIiM.js} +5 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-BEvGBtb_.js → duplicate-BINwP0WG.js} +1 -1
- package/dist/{gameplay-Dn3yidJw.js → gameplay-sSqrUcnz.js} +75 -3
- package/dist/gameplay.d.ts +37 -2
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/{loader-B4OEXDZ8.js → loader-BZqOKfI2.js} +3 -1
- package/dist/{loader-BcUDfNHn.d.ts → loader-DILt9PGC.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +3 -3
- package/dist/{pathfinding-BSiXjd6W.d.ts → pathfinding-RWYkNKx9.d.ts} +1 -1
- package/dist/{physics-2d-B6D864oZ.js → physics-2d-BiIdl51r.js} +2 -2
- package/dist/{physics-3d-RLNaxRyw.js → physics-3d-D_kUdOjr.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-Cwc-yCYx.js → register-BFFE1Mh1.js} +2 -2
- package/dist/{register-ysLR3WQS.js → register-C9-16x_t.js} +562 -157
- package/dist/{register-BD6zgrv_.js → register-Djwckzgx.js} +2 -2
- package/dist/{register-DJZXxwAn.js → register-nObreUQR.js} +1 -1
- package/dist/test.d.ts +2 -2
- package/dist/test.js +10 -10
- package/editor/assets/{agent8-D_4QY8Aq.js → agent8-BDC4LhjC.js} +1 -1
- package/editor/assets/{index-s0DZuroe.js → index-7qOYg7t8.js} +74 -74
- package/editor/index.html +1 -1
- package/package.json +4 -2
- package/schemas/scene.schema.json +266 -6
- package/skills/incanto-3d-character.md +35 -0
- package/skills/incanto-building-3d-games.md +48 -0
- package/skills/incanto-environment.md +15 -16
- package/skills/incanto-gameplay-behaviors.md +23 -1
- package/skills/incanto-node-reference.md +54 -3
- package/templates-app/beacon-isle-3d/PROJECT/Context.md +44 -0
- package/templates-app/beacon-isle-3d/PROJECT/Requirements.md +16 -0
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +38 -0
- package/templates-app/beacon-isle-3d/PROJECT/Structure.md +24 -0
- package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +38 -0
- package/templates-app/beacon-isle-3d/generate-world.ts +812 -0
- package/templates-app/beacon-isle-3d/index.html +68 -0
- package/templates-app/beacon-isle-3d/package.json +26 -0
- package/templates-app/beacon-isle-3d/src/behaviors.ts +570 -0
- package/templates-app/beacon-isle-3d/src/game.scene.json +2969 -0
- package/templates-app/beacon-isle-3d/src/main.ts +33 -0
- package/templates-app/beacon-isle-3d/tsconfig.json +13 -0
- package/templates-app/beacon-isle-3d/verify.ts +285 -0
- package/templates-app/beacon-isle-3d/vite.config.ts +5 -0
- package/templates-app/tps-3d/PROJECT/Context.md +49 -0
- package/templates-app/tps-3d/PROJECT/Requirements.md +38 -0
- package/templates-app/tps-3d/PROJECT/Status.md +41 -0
- package/templates-app/tps-3d/PROJECT/Structure.md +44 -0
- package/templates-app/tps-3d/docs/project-3d-rules.md +38 -0
- package/templates-app/tps-3d/index.html +244 -0
- package/templates-app/tps-3d/package.json +25 -0
- package/templates-app/tps-3d/src/behaviors.ts +405 -0
- package/templates-app/tps-3d/src/game.scene.json +677 -0
- package/templates-app/tps-3d/src/main.ts +64 -0
- package/templates-app/tps-3d/tsconfig.json +13 -0
- package/templates-app/tps-3d/verify.ts +167 -0
- package/templates-app/tps-3d/vite.config.ts +5 -0
- package/templates-app/village-quest-3d/PROJECT/Context.md +39 -0
- package/templates-app/village-quest-3d/PROJECT/Requirements.md +36 -0
- package/templates-app/village-quest-3d/PROJECT/Status.md +26 -0
- package/templates-app/village-quest-3d/PROJECT/Structure.md +30 -0
- package/templates-app/village-quest-3d/docs/project-3d-rules.md +38 -0
- package/templates-app/village-quest-3d/index.html +68 -0
- package/templates-app/village-quest-3d/package.json +25 -0
- package/templates-app/village-quest-3d/src/behaviors.ts +529 -0
- package/templates-app/village-quest-3d/src/grove.scene.json +826 -0
- package/templates-app/village-quest-3d/src/main.ts +35 -0
- package/templates-app/village-quest-3d/src/quest.ts +18 -0
- package/templates-app/village-quest-3d/src/village.scene.json +680 -0
- package/templates-app/village-quest-3d/tsconfig.json +13 -0
- package/templates-app/village-quest-3d/verify.ts +254 -0
- package/templates-app/village-quest-3d/vite.config.ts +5 -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-7qOYg7t8.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-D8QvwvOm.css">
|
|
11
11
|
</head>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incanto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game-engine",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"skills",
|
|
28
28
|
"bin",
|
|
29
29
|
"editor",
|
|
30
|
+
"templates-app",
|
|
30
31
|
"assets",
|
|
31
32
|
"LICENSE",
|
|
32
33
|
"THIRD-PARTY-NOTICES.md"
|
|
@@ -92,6 +93,7 @@
|
|
|
92
93
|
"incanto-check": "bin/incanto-check.mjs",
|
|
93
94
|
"incanto-assets": "bin/incanto-assets.mjs",
|
|
94
95
|
"incanto-env": "bin/incanto-env.mjs",
|
|
95
|
-
"incanto-play": "bin/incanto-play.mjs"
|
|
96
|
+
"incanto-play": "bin/incanto-play.mjs",
|
|
97
|
+
"incanto-new": "bin/incanto-new.mjs"
|
|
96
98
|
}
|
|
97
99
|
}
|
|
@@ -193,6 +193,9 @@
|
|
|
193
193
|
{
|
|
194
194
|
"$ref": "#/$defs/BoneAttachment3D"
|
|
195
195
|
},
|
|
196
|
+
{
|
|
197
|
+
"$ref": "#/$defs/BoneLookAt3D"
|
|
198
|
+
},
|
|
196
199
|
{
|
|
197
200
|
"$ref": "#/$defs/Camera2D"
|
|
198
201
|
},
|
|
@@ -226,6 +229,9 @@
|
|
|
226
229
|
{
|
|
227
230
|
"$ref": "#/$defs/HudLayer"
|
|
228
231
|
},
|
|
232
|
+
{
|
|
233
|
+
"$ref": "#/$defs/InstancedMesh3D"
|
|
234
|
+
},
|
|
229
235
|
{
|
|
230
236
|
"$ref": "#/$defs/Joint2D"
|
|
231
237
|
},
|
|
@@ -1196,6 +1202,126 @@
|
|
|
1196
1202
|
},
|
|
1197
1203
|
"required": ["name", "type"]
|
|
1198
1204
|
},
|
|
1205
|
+
"BoneLookAt3D": {
|
|
1206
|
+
"type": "object",
|
|
1207
|
+
"properties": {
|
|
1208
|
+
"name": {
|
|
1209
|
+
"type": "string"
|
|
1210
|
+
},
|
|
1211
|
+
"uid": {
|
|
1212
|
+
"type": "string"
|
|
1213
|
+
},
|
|
1214
|
+
"type": {
|
|
1215
|
+
"const": "BoneLookAt3D"
|
|
1216
|
+
},
|
|
1217
|
+
"groups": {
|
|
1218
|
+
"type": "array",
|
|
1219
|
+
"items": {
|
|
1220
|
+
"type": "string"
|
|
1221
|
+
}
|
|
1222
|
+
},
|
|
1223
|
+
"tags": {
|
|
1224
|
+
"type": "object"
|
|
1225
|
+
},
|
|
1226
|
+
"props": {
|
|
1227
|
+
"type": "object",
|
|
1228
|
+
"properties": {
|
|
1229
|
+
"position": {
|
|
1230
|
+
"type": "array",
|
|
1231
|
+
"items": {
|
|
1232
|
+
"type": "number"
|
|
1233
|
+
},
|
|
1234
|
+
"minItems": 3,
|
|
1235
|
+
"maxItems": 3,
|
|
1236
|
+
"default": [0, 0, 0]
|
|
1237
|
+
},
|
|
1238
|
+
"rotation": {
|
|
1239
|
+
"type": "array",
|
|
1240
|
+
"items": {
|
|
1241
|
+
"type": "number"
|
|
1242
|
+
},
|
|
1243
|
+
"minItems": 3,
|
|
1244
|
+
"maxItems": 3,
|
|
1245
|
+
"default": [0, 0, 0]
|
|
1246
|
+
},
|
|
1247
|
+
"static": {
|
|
1248
|
+
"type": "boolean",
|
|
1249
|
+
"default": false
|
|
1250
|
+
},
|
|
1251
|
+
"scale": {
|
|
1252
|
+
"type": "array",
|
|
1253
|
+
"items": {
|
|
1254
|
+
"type": "number"
|
|
1255
|
+
},
|
|
1256
|
+
"minItems": 3,
|
|
1257
|
+
"maxItems": 3,
|
|
1258
|
+
"default": [1, 1, 1]
|
|
1259
|
+
},
|
|
1260
|
+
"visible": {
|
|
1261
|
+
"type": "boolean",
|
|
1262
|
+
"default": true
|
|
1263
|
+
},
|
|
1264
|
+
"renderOrder": {
|
|
1265
|
+
"type": "number",
|
|
1266
|
+
"default": 0
|
|
1267
|
+
},
|
|
1268
|
+
"orderGroup": {
|
|
1269
|
+
"type": "string",
|
|
1270
|
+
"enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
|
|
1271
|
+
"default": "default"
|
|
1272
|
+
},
|
|
1273
|
+
"target": {
|
|
1274
|
+
"type": "string",
|
|
1275
|
+
"default": ""
|
|
1276
|
+
},
|
|
1277
|
+
"bone": {
|
|
1278
|
+
"type": "string",
|
|
1279
|
+
"default": "Head"
|
|
1280
|
+
},
|
|
1281
|
+
"lookAt": {
|
|
1282
|
+
"type": "string",
|
|
1283
|
+
"default": ""
|
|
1284
|
+
},
|
|
1285
|
+
"maxAngleDeg": {
|
|
1286
|
+
"type": "number",
|
|
1287
|
+
"default": 75
|
|
1288
|
+
},
|
|
1289
|
+
"weight": {
|
|
1290
|
+
"type": "number",
|
|
1291
|
+
"default": 0.85
|
|
1292
|
+
},
|
|
1293
|
+
"forwardAxis": {
|
|
1294
|
+
"type": "string",
|
|
1295
|
+
"enum": ["+x", "-x", "+y", "-y", "+z", "-z"],
|
|
1296
|
+
"default": "+z"
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
"additionalProperties": false
|
|
1300
|
+
},
|
|
1301
|
+
"script": {
|
|
1302
|
+
"type": "object",
|
|
1303
|
+
"properties": {
|
|
1304
|
+
"name": {
|
|
1305
|
+
"type": "string"
|
|
1306
|
+
},
|
|
1307
|
+
"props": {
|
|
1308
|
+
"type": "object"
|
|
1309
|
+
}
|
|
1310
|
+
},
|
|
1311
|
+
"required": ["name"]
|
|
1312
|
+
},
|
|
1313
|
+
"network": {
|
|
1314
|
+
"type": "object"
|
|
1315
|
+
},
|
|
1316
|
+
"children": {
|
|
1317
|
+
"type": "array",
|
|
1318
|
+
"items": {
|
|
1319
|
+
"$ref": "#/$defs/node"
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
},
|
|
1323
|
+
"required": ["name", "type"]
|
|
1324
|
+
},
|
|
1199
1325
|
"Camera2D": {
|
|
1200
1326
|
"type": "object",
|
|
1201
1327
|
"properties": {
|
|
@@ -2245,8 +2371,7 @@
|
|
|
2245
2371
|
"default": 0.5
|
|
2246
2372
|
},
|
|
2247
2373
|
"drape": {
|
|
2248
|
-
"
|
|
2249
|
-
"default": false
|
|
2374
|
+
"default": null
|
|
2250
2375
|
},
|
|
2251
2376
|
"terrain": {
|
|
2252
2377
|
"type": "string",
|
|
@@ -2433,8 +2558,7 @@
|
|
|
2433
2558
|
"default": 1
|
|
2434
2559
|
},
|
|
2435
2560
|
"drape": {
|
|
2436
|
-
"
|
|
2437
|
-
"default": false
|
|
2561
|
+
"default": null
|
|
2438
2562
|
},
|
|
2439
2563
|
"terrain": {
|
|
2440
2564
|
"type": "string",
|
|
@@ -2526,6 +2650,131 @@
|
|
|
2526
2650
|
},
|
|
2527
2651
|
"required": ["name", "type"]
|
|
2528
2652
|
},
|
|
2653
|
+
"InstancedMesh3D": {
|
|
2654
|
+
"type": "object",
|
|
2655
|
+
"properties": {
|
|
2656
|
+
"name": {
|
|
2657
|
+
"type": "string"
|
|
2658
|
+
},
|
|
2659
|
+
"uid": {
|
|
2660
|
+
"type": "string"
|
|
2661
|
+
},
|
|
2662
|
+
"type": {
|
|
2663
|
+
"const": "InstancedMesh3D"
|
|
2664
|
+
},
|
|
2665
|
+
"groups": {
|
|
2666
|
+
"type": "array",
|
|
2667
|
+
"items": {
|
|
2668
|
+
"type": "string"
|
|
2669
|
+
}
|
|
2670
|
+
},
|
|
2671
|
+
"tags": {
|
|
2672
|
+
"type": "object"
|
|
2673
|
+
},
|
|
2674
|
+
"props": {
|
|
2675
|
+
"type": "object",
|
|
2676
|
+
"properties": {
|
|
2677
|
+
"position": {
|
|
2678
|
+
"type": "array",
|
|
2679
|
+
"items": {
|
|
2680
|
+
"type": "number"
|
|
2681
|
+
},
|
|
2682
|
+
"minItems": 3,
|
|
2683
|
+
"maxItems": 3,
|
|
2684
|
+
"default": [0, 0, 0]
|
|
2685
|
+
},
|
|
2686
|
+
"rotation": {
|
|
2687
|
+
"type": "array",
|
|
2688
|
+
"items": {
|
|
2689
|
+
"type": "number"
|
|
2690
|
+
},
|
|
2691
|
+
"minItems": 3,
|
|
2692
|
+
"maxItems": 3,
|
|
2693
|
+
"default": [0, 0, 0]
|
|
2694
|
+
},
|
|
2695
|
+
"static": {
|
|
2696
|
+
"type": "boolean",
|
|
2697
|
+
"default": false
|
|
2698
|
+
},
|
|
2699
|
+
"scale": {
|
|
2700
|
+
"type": "array",
|
|
2701
|
+
"items": {
|
|
2702
|
+
"type": "number"
|
|
2703
|
+
},
|
|
2704
|
+
"minItems": 3,
|
|
2705
|
+
"maxItems": 3,
|
|
2706
|
+
"default": [1, 1, 1]
|
|
2707
|
+
},
|
|
2708
|
+
"visible": {
|
|
2709
|
+
"type": "boolean",
|
|
2710
|
+
"default": true
|
|
2711
|
+
},
|
|
2712
|
+
"renderOrder": {
|
|
2713
|
+
"type": "number",
|
|
2714
|
+
"default": 0
|
|
2715
|
+
},
|
|
2716
|
+
"orderGroup": {
|
|
2717
|
+
"type": "string",
|
|
2718
|
+
"enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
|
|
2719
|
+
"default": "default"
|
|
2720
|
+
},
|
|
2721
|
+
"mesh": {
|
|
2722
|
+
"type": "string",
|
|
2723
|
+
"enum": ["box", "sphere", "capsule", "plane", "cylinder", "gem"],
|
|
2724
|
+
"default": "box"
|
|
2725
|
+
},
|
|
2726
|
+
"size": {
|
|
2727
|
+
"type": "array",
|
|
2728
|
+
"items": {
|
|
2729
|
+
"type": "number"
|
|
2730
|
+
},
|
|
2731
|
+
"minItems": 3,
|
|
2732
|
+
"maxItems": 3,
|
|
2733
|
+
"default": [1, 1, 1]
|
|
2734
|
+
},
|
|
2735
|
+
"material": {
|
|
2736
|
+
"type": "object",
|
|
2737
|
+
"default": {}
|
|
2738
|
+
},
|
|
2739
|
+
"transforms": {
|
|
2740
|
+
"type": "array",
|
|
2741
|
+
"default": []
|
|
2742
|
+
},
|
|
2743
|
+
"castShadow": {
|
|
2744
|
+
"type": "boolean",
|
|
2745
|
+
"default": false
|
|
2746
|
+
},
|
|
2747
|
+
"receiveShadow": {
|
|
2748
|
+
"type": "boolean",
|
|
2749
|
+
"default": false
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
"additionalProperties": false
|
|
2753
|
+
},
|
|
2754
|
+
"script": {
|
|
2755
|
+
"type": "object",
|
|
2756
|
+
"properties": {
|
|
2757
|
+
"name": {
|
|
2758
|
+
"type": "string"
|
|
2759
|
+
},
|
|
2760
|
+
"props": {
|
|
2761
|
+
"type": "object"
|
|
2762
|
+
}
|
|
2763
|
+
},
|
|
2764
|
+
"required": ["name"]
|
|
2765
|
+
},
|
|
2766
|
+
"network": {
|
|
2767
|
+
"type": "object"
|
|
2768
|
+
},
|
|
2769
|
+
"children": {
|
|
2770
|
+
"type": "array",
|
|
2771
|
+
"items": {
|
|
2772
|
+
"$ref": "#/$defs/node"
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
},
|
|
2776
|
+
"required": ["name", "type"]
|
|
2777
|
+
},
|
|
2529
2778
|
"Joint2D": {
|
|
2530
2779
|
"type": "object",
|
|
2531
2780
|
"properties": {
|
|
@@ -3228,6 +3477,18 @@
|
|
|
3228
3477
|
"type": "boolean",
|
|
3229
3478
|
"default": true
|
|
3230
3479
|
},
|
|
3480
|
+
"animationUpper": {
|
|
3481
|
+
"type": "string",
|
|
3482
|
+
"default": ""
|
|
3483
|
+
},
|
|
3484
|
+
"animationUpperLoop": {
|
|
3485
|
+
"type": "boolean",
|
|
3486
|
+
"default": false
|
|
3487
|
+
},
|
|
3488
|
+
"upperBodyRoot": {
|
|
3489
|
+
"type": "string",
|
|
3490
|
+
"default": "Spine"
|
|
3491
|
+
},
|
|
3231
3492
|
"receiveShadow": {
|
|
3232
3493
|
"type": "boolean",
|
|
3233
3494
|
"default": false
|
|
@@ -5393,8 +5654,7 @@
|
|
|
5393
5654
|
"default": true
|
|
5394
5655
|
},
|
|
5395
5656
|
"drape": {
|
|
5396
|
-
"
|
|
5397
|
-
"default": false
|
|
5657
|
+
"default": null
|
|
5398
5658
|
},
|
|
5399
5659
|
"terrain": {
|
|
5400
5660
|
"type": "string",
|
|
@@ -102,6 +102,25 @@ shambling clip + glowing eyes for an enemy that reads as a different creature.
|
|
|
102
102
|
"animation": "$walk", "castShadow": true } }
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
## Two-layer animation: attack WHILE running (`animationUpper`)
|
|
106
|
+
|
|
107
|
+
A single `animation` clip owns the whole body — setting an attack clip freezes
|
|
108
|
+
the legs. The UPPER LAYER fixes that:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
skin.animationUpper = '$anims/attack'; // spine-up plays the attack…
|
|
112
|
+
// …while `animation` (idle/run via the controller) keeps driving the legs.
|
|
113
|
+
// One-shots AUTO-CLEAR when the clip ends (and emit animationFinished) —
|
|
114
|
+
// set it per attack and forget it.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `upperBodyRoot` (default `'Spine'`, Mixamo spellings matched) picks the bone
|
|
118
|
+
subtree the layer owns; the base clip is automatically masked to the rest,
|
|
119
|
+
so there's no half-blended overlap and no stride reset (time stays aligned).
|
|
120
|
+
- `animationUpperLoop: true` for sustained upper loops (carry, aim, wave).
|
|
121
|
+
- Works with the controller's `animations` map untouched — locomotion logic
|
|
122
|
+
never learns the attack exists.
|
|
123
|
+
|
|
105
124
|
## Animations without code
|
|
106
125
|
|
|
107
126
|
Map movement states straight in JSON — no behavior needed:
|
|
@@ -149,6 +168,22 @@ A sword in the hand, a hat on the head, sparks on a wingtip — parent them to a
|
|
|
149
168
|
- `model.boneNames()` lists every bone at runtime when you need to hunt one
|
|
150
169
|
(the editor's inspector offers the same list as a dropdown on the `bone` prop).
|
|
151
170
|
|
|
171
|
+
## Heads that WATCH things (`BoneLookAt3D`)
|
|
172
|
+
|
|
173
|
+
NPCs feel alive when they track you. One node, zero code:
|
|
174
|
+
|
|
175
|
+
```jsonc
|
|
176
|
+
{ "name": "HeadTrack", "type": "BoneLookAt3D",
|
|
177
|
+
"props": { "target": "../Body", "bone": "Head", "lookAt": "%Player" } }
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- Runs on top of the playing animation each frame; blends in/out smoothly and
|
|
181
|
+
DISENGAGES when the target leaves the `maxAngleDeg` comfort cone (75° —
|
|
182
|
+
no owl necks).
|
|
183
|
+
- `weight` (0.85) is how far the head commits; `forwardAxis` defaults to the
|
|
184
|
+
mixamo head convention (+z).
|
|
185
|
+
- Also good for chests (`bone: "Spine2"`, small weight) and turrets.
|
|
186
|
+
|
|
152
187
|
## Facing a direction in 3D — the +Z-FORWARD rule (read before turning ANY skin)
|
|
153
188
|
|
|
154
189
|
This trips people up REPEATEDLY, so here is the one rule. agent8's `base-model` (and
|
|
@@ -17,6 +17,19 @@ GLB/glTF/VRM files load via `ModelInstance3D` — see `incanto-3d-models.md` for
|
|
|
17
17
|
asset declaration, `targetHeight` sizing, and the `bunx incanto-model` inspector that
|
|
18
18
|
reports a file's real bounding box and animation names.
|
|
19
19
|
|
|
20
|
+
## Fastest start: scaffold a whole game
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bunx incanto-new my-game # Beacon Isle — 3D flagship template
|
|
24
|
+
bunx incanto-new my-game --template tps-3d # third-person shooter starter
|
|
25
|
+
bunx incanto-new --list
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Templates are COMPLETE games (world generation, quest, enemies, verify
|
|
29
|
+
harness) meant to be reshaped — regenerate the Beacon Isle world with
|
|
30
|
+
`bun run world`, keep the game logic. Prefer starting from one over wiring
|
|
31
|
+
from scratch.
|
|
32
|
+
|
|
20
33
|
## Boot sequence (the only TypeScript you need to start)
|
|
21
34
|
|
|
22
35
|
```ts
|
|
@@ -65,6 +78,28 @@ All 3D nodes extend `Node3D` and therefore have the transform props:
|
|
|
65
78
|
| `material` | `{}` | `{color: '#hex', metalness: 0..1, roughness: 0..1, opacity: 0..1, clearcoat: 0..1, clearcoatRoughness: 0..1, envMapIntensity: >=0, wireframe, flatShading, depthTest, depthWrite, emissive, emissiveIntensity, map, normalMap, repeat: [u,v]}` — the object IS the material state: omitted keys reset to defaults (`#ffffff`, 0, 1, 1, false, false, depthTest/Write true). `opacity < 1` turns on transparency; `flatShading` gives faceted per-face glints (the gem sparkle). `depthTest: false` (+ a high `renderOrder`) makes a flat `plane`/`cylinder` an ALWAYS-ON-TOP ground decal — AoE telegraphs, selection/spawn rings — that never z-fights with or is hidden by bumpy terrain (`depthWrite: false` keeps it from occluding later effects). `map`/`normalMap` are texture URLs (lazy-loaded, headless-safe; map samples sRGB, normalMap linear), tiled `repeat` times across each face — box/plane UVs span 0..1 per face, so for worldspace density use `repeat: [length/tile, height/tile]` (e.g. a 6×2.5 m brick wall at one tile per 2 m → `[3, 1.25]`). `color` tints the map (near-white keeps the texture's own color). CAR PAINT: `clearcoat: 1` adds a glossy lacquer layer with its own reflection over a metallic base (`clearcoatRoughness` ~0.05-0.1 = mirror lacquer) — THE premium vehicle-paint look; `envMapIntensity` scales how strongly the surface mirrors the scene's sky/HDRI (glass windows want ~2, matte surfaces <1; needs a `sky`/`hdri` environment to reflect — at night with no sky there is nothing to mirror). NB: under ACES a very bright `emissiveIntensity` blows out to white — keep it modest (~1–2) + a saturated color for a vivid GLOWING look. Unknown keys, malformed `repeat`, or `repeat` without a map hard-fail at load |
|
|
66
79
|
| `castShadow` / `receiveShadow` | `false` | |
|
|
67
80
|
|
|
81
|
+
### `InstancedMesh3D` (hundreds of props, one draw call)
|
|
82
|
+
|
|
83
|
+
Scattered rocks, fence posts, crates, gravestones — identical meshes should
|
|
84
|
+
never be one node each. One instanced node draws them all at once:
|
|
85
|
+
|
|
86
|
+
```jsonc
|
|
87
|
+
{ "name": "Rocks", "type": "InstancedMesh3D",
|
|
88
|
+
"props": { "mesh": "gem", "size": [0.7, 0.5, 0.7],
|
|
89
|
+
"material": { "color": "#8a8f98", "roughness": 0.95, "flatShading": true },
|
|
90
|
+
"transforms": [
|
|
91
|
+
[12.2, 0.1, -8.4, 40, 1.3],
|
|
92
|
+
[-6.0, 0.2, 14.1, 210, 0.8],
|
|
93
|
+
[3.5, 0.0, 22.7, 118, 1.0]
|
|
94
|
+
] } }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Each row: `[x, y, z, yawDeg?, scale?]` — dense enough to GENERATE hundreds
|
|
98
|
+
(pair with `terrain.heightAt` for y).
|
|
99
|
+
- Same `mesh`/`size`/`material` surface as MeshInstance3D. Replace the whole
|
|
100
|
+
`transforms` array to update. No per-instance colliders — add a few
|
|
101
|
+
StaticBody3D boxes only where gameplay needs blocking.
|
|
102
|
+
|
|
68
103
|
### `LoftMesh3D` (smooth swept hulls — vehicle bodies, canopies)
|
|
69
104
|
|
|
70
105
|
A SMOOTH curved surface swept through cross-sections — what box/capsule assemblies can
|
|
@@ -291,6 +326,15 @@ demo into a commercial-looking outdoor scene:
|
|
|
291
326
|
offscreen pass. The fastest way to give a scene a LOOK: dusk = vignette 0.35
|
|
292
327
|
+ saturation 0.85, candy = saturation 1.25 + contrast 1.08. Caustics/clouds
|
|
293
328
|
composites take precedence (pipelines don't stack yet).
|
|
329
|
+
- **Runtime changes**: the renderer re-reads `environment` every frame — call
|
|
330
|
+
`setEnvironment3D(engine, { sky: { elevationDeg: 4 }, exposure: 0.8 })`
|
|
331
|
+
(from `incanto/3d`) to change the look LIVE. One-level deep merge, `null`
|
|
332
|
+
deletes a key, and a bad patch throws in YOUR call stack, never mid-render.
|
|
333
|
+
For a full day/night loop, attach the built-in `DayNight` behavior instead:
|
|
334
|
+
`{ "script": { "name": "DayNight", "props": { "daySeconds": 240 } } }` —
|
|
335
|
+
sun arc + ambient/exposure ramps + a `dayPhaseChanged(dawn|day|dusk|night)`
|
|
336
|
+
signal to hook spawners/music to. Its `hour` field is writable (jump to a
|
|
337
|
+
time, or `paused: true` and animate it yourself).
|
|
294
338
|
- `shadows`: `true` | `false` | `{ "mapSize": 1024|2048, "radius": n }`.
|
|
295
339
|
Truthy makes the main DirectionalLight cast (PCF soft, terrain + trees +
|
|
296
340
|
meshes cast/receive, mesh grass RECEIVES only). One static ortho box (±75 m
|
|
@@ -422,6 +466,10 @@ if (cells) follow.setPath(cells.map(([cx, cy]) => nav.toWorld(cx, cy)));
|
|
|
422
466
|
`nav.setSolid(...nav.toCell(x, z))` after building.
|
|
423
467
|
- Walkability is judged inside each cell (corner samples), so a flat trail
|
|
424
468
|
beside a cliff stays walkable — only genuinely steep cells go solid.
|
|
469
|
+
- **See what the enemies see**: `root.addChild(createNavDebugNode(nav))`
|
|
470
|
+
paints every walkable cell as a translucent quad on the surface (one
|
|
471
|
+
instanced draw call) — add while tuning `cellSize`/`maxSlopeDeg`, drop when
|
|
472
|
+
the routes look right.
|
|
425
473
|
|
|
426
474
|
## Performance levers for big scenes
|
|
427
475
|
|
|
@@ -358,14 +358,13 @@ tops radially away with a smooth falloff as a character wades through.
|
|
|
358
358
|
| `coverage` | `0.85` | mesh: carpet fill in (0, 1] — below 1 noise carves dirt patches (load-time check) |
|
|
359
359
|
| `flowers` | `0` | DEPRECATED — confetti heads; use a `Flowers3D` node (load-time check 0–0.2) |
|
|
360
360
|
| `seed` | `1` | placement seed — identical field across runs/machines |
|
|
361
|
-
| `drape` | `
|
|
362
|
-
| `terrain` | `""` | drape target node path; empty = **auto-find the first Terrain3D** in the tree
|
|
361
|
+
| `drape` | `null` | **AUTO by default**: whenever the scene has a Terrain3D, every blade roots on the ground under it (samples `heightAt`) — omit this prop and rolling terrain just works. `true` forces it (keeps retrying until a terrain appears — streamed worlds), `false` opts out (flat carpet at the node's Y) |
|
|
362
|
+
| `terrain` | `""` | drape target node path; empty = **auto-find the first Terrain3D** in the tree. A non-empty path that is NOT a Terrain3D fails at load — no silent floating |
|
|
363
363
|
|
|
364
|
-
> **Rolling terrain
|
|
365
|
-
>
|
|
366
|
-
>
|
|
367
|
-
>
|
|
368
|
-
> generators still do the latter for backward-compatible output).
|
|
364
|
+
> **Rolling terrain just works.** Since 0.14 draping is on by default: with a
|
|
365
|
+
> Terrain3D in the scene the blades root on the ground per-instance, no wiring.
|
|
366
|
+
> Only set `drape: false` if you WANT a flat carpet at the node's Y (e.g. grass
|
|
367
|
+
> on a flat MeshInstance3D platform above the terrain).
|
|
369
368
|
|
|
370
369
|
## Flowers3D
|
|
371
370
|
|
|
@@ -415,8 +414,8 @@ billboard confetti. Deterministic from the `seed` PROP.
|
|
|
415
414
|
| `height` | `0.45` | plant height, meters (±25% per-plant jitter) |
|
|
416
415
|
| `clustering` | `0.6` | 0 uniform … 1 tight Voronoi patches (load-time check) |
|
|
417
416
|
| `sway` | `0.5` | head-bob wind strength; 0 disables |
|
|
418
|
-
| `drape` | `
|
|
419
|
-
| `terrain` | `""` | drape target node path; empty = auto-find the first Terrain3D |
|
|
417
|
+
| `drape` | `null` | AUTO by default — plants root on the scene's Terrain3D when one exists; `true` forces, `false` opts out — see the Foliage3D drape note above |
|
|
418
|
+
| `terrain` | `""` | drape target node path; empty = auto-find the first Terrain3D (a wrong path fails at load) |
|
|
420
419
|
|
|
421
420
|
## Tree3D
|
|
422
421
|
Procedural trees grown by the ported ez-tree generator (MIT, Dan Greenheck;
|
|
@@ -484,8 +483,8 @@ Every instance in a grove also gets a deterministic per-instance color jitter (
|
|
|
484
483
|
| `leafFadeStart` | `0` | **leaf LOD** — leaf cards begin collapsing toward their branch at this camera distance (m). `0`/`0` disables (full leaves at any range) |
|
|
485
484
|
| `leafFadeEnd` | `0` | leaf LOD — cards fully collapsed (zero overdraw) by here; tune ≈ the scene `fog.far` so the thinning hides in fog (load-time check: `> leafFadeStart`) |
|
|
486
485
|
| `leafShadows` | `true` | `false` keeps trunk/branch shadows but drops the expensive alpha-cutout LEAF shadow pass — big FPS in dense forests |
|
|
487
|
-
| `drape` | `
|
|
488
|
-
| `terrain` | `""` | drape target node path; empty = auto-find the first Terrain3D (
|
|
486
|
+
| `drape` | `null` | AUTO by default: each scattered instance roots at the ground height under it (instead of the node's single Y) whenever the scene has a Terrain3D — a `count > 1` grove on rolling/carved terrain never floats or buries. `true` forces, `false` opts out |
|
|
487
|
+
| `terrain` | `""` | drape target node path; empty = auto-find the first Terrain3D (a wrong path fails at load) |
|
|
489
488
|
|
|
490
489
|
> **Tree LOD / forest FPS.** Leaf overdraw + the leaf shadow pass dominate a
|
|
491
490
|
> dense-forest frame (~90% in profiling). For big groves set `leafFadeStart`/
|
|
@@ -493,11 +492,11 @@ Every instance in a grove also gets a deterministic per-instance color jitter (
|
|
|
493
492
|
> leaf cards (branch silhouette stays), and `leafShadows: false` to drop the leaf
|
|
494
493
|
> shadow pass. Both default off → existing scenes are unchanged.
|
|
495
494
|
|
|
496
|
-
> **Floating trees?**
|
|
497
|
-
>
|
|
498
|
-
>
|
|
499
|
-
>
|
|
500
|
-
>
|
|
495
|
+
> **Floating trees?** Since 0.14 groves drape automatically whenever the scene
|
|
496
|
+
> has a Terrain3D — each instance roots on the ground under it. The drape is a
|
|
497
|
+
> pure heightAt lookup — no rng draw, so the seed/grove layout is
|
|
498
|
+
> byte-identical, only the Y shifts. `drape: false` restores the flat
|
|
499
|
+
> single-Y placement.
|
|
501
500
|
|
|
502
501
|
## Terrain3D
|
|
503
502
|
Procedural heightfield terrain with biome texture splatting (in `incanto/3d`,
|
|
@@ -749,7 +749,29 @@ Multi-scene games: `flow.goToScene(nextSceneJson, { fadeSeconds: 0.4 })`
|
|
|
749
749
|
fades to black, swaps, fades back (headless = instant). Title → level →
|
|
750
750
|
next level is three JSON files and this one call.
|
|
751
751
|
|
|
752
|
-
##
|
|
752
|
+
## DayNight (live 24-hour cycle)
|
|
753
|
+
|
|
754
|
+
Drives the scene `environment` (needs an atmosphere sky): sun elevation/
|
|
755
|
+
azimuth arc, ambient + exposure ramps with a moonlight floor.
|
|
756
|
+
|
|
757
|
+
```jsonc
|
|
758
|
+
{ "script": { "name": "DayNight", "props": { "daySeconds": 240, "startHour": 9 } } }
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
| Prop | Default | Notes |
|
|
762
|
+
|---|---|---|
|
|
763
|
+
| `daySeconds` | 240 | real seconds per full day |
|
|
764
|
+
| `startHour` | 10 | 0-24 clock at scene start |
|
|
765
|
+
| `maxSunElevationDeg` | 55 | noon height |
|
|
766
|
+
| `nightDarkness` | 0.75 | 0 = night looks like day, 1 = black |
|
|
767
|
+
| `paused` | false | freeze the clock; write `hour` yourself |
|
|
768
|
+
|
|
769
|
+
Signals: `dayPhaseChanged('dawn'|'day'|'dusk'|'night')` on transitions — hook
|
|
770
|
+
spawners, music, or monster aggression to it. The `hour` field (0-24) is
|
|
771
|
+
writable: jump to a time of day in one assignment. For one-off look changes
|
|
772
|
+
use `setEnvironment3D(engine, patch)` from `incanto/3d` directly.
|
|
773
|
+
|
|
774
|
+
## Boot loading overlay## Boot loading overlay
|
|
753
775
|
|
|
754
776
|
```ts
|
|
755
777
|
import { preloadSceneAssets } from 'incanto';
|