incanto 0.34.0 → 0.35.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/dist/2d.d.ts +5 -5
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +122 -14
- package/dist/3d.js +5 -5
- package/dist/{audit-C4kmDK0o.js → audit-C5oZGAru.js} +37 -0
- package/dist/{behavior-CtPScDMo.d.ts → behavior-CGSCWOHB.d.ts} +310 -22
- package/dist/{create-game-CFNqoqOX.js → create-game-B0Wfhi2-.js} +6 -5
- package/dist/{create-game-QTfghzwM.js → create-game-BUD89Kqh.js} +20 -6
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-DlOvknDO.js → duplicate-C716f-97.js} +1 -1
- package/dist/{editor-switch-BJb-CWfA.d.ts → editor-switch-DyXEtH36.d.ts} +1 -1
- package/dist/editor.js +1739 -1312
- package/dist/env.d.ts +1 -1
- package/dist/{environment-presets-B6WiUsaO.js → environment-presets-TAGvmM3z.js} +240 -74
- package/dist/{errors-1dXlIwoR.d.ts → errors-BY2kL0hv.d.ts} +1 -1
- package/dist/{gameplay-BxFtmfSe.js → gameplay-BvhcQbfJ.js} +75 -11
- package/dist/gameplay.d.ts +12 -5
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +22 -7
- package/dist/index.js +6 -6
- package/dist/{loader-DmXfj6Uv.d.ts → loader-CUcj00M8.d.ts} +19 -2
- package/dist/{loader-BwR0DxeM.js → loader-Mig5fY4n.js} +97 -18
- package/dist/net.d.ts +2 -2
- package/dist/net.js +3 -3
- package/dist/{particle-sim-CwJ5rI_P.d.ts → particle-sim-B-vZBF5R.d.ts} +1 -1
- package/dist/{pathfinding-DRCe89SI.d.ts → pathfinding-DgOo2KNF.d.ts} +1 -1
- package/dist/{physics-2d-BuyAwsW5.js → physics-2d-DqAclql-.js} +22 -9
- package/dist/{physics-3d-C8Kn_Nyb.js → physics-3d-DxBH4sIF.js} +27 -11
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/{register-G3edsjJ2.js → register-BFLg0-_i.js} +490 -12
- package/dist/{register-OodmuUMK.js → register-BjbPMA5B.js} +2 -2
- package/dist/{register-BLPC10Mj.js → register-DSmIRAf7.js} +11 -5
- package/dist/{schema-CcoWb32N.d.ts → schema-3ywbdlrv.d.ts} +10 -0
- package/dist/{test-C4B5znap.js → test-9EokzbRd.js} +10 -10
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +1 -1
- package/editor/assets/{agent8-BTODHtdM.js → agent8-D3_GWeuh.js} +1 -1
- package/editor/assets/{debug-CJEz4EwC.js → debug-CX0LDd1r.js} +1 -1
- package/editor/assets/index-CMlKFT0C.js +10773 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +109 -0
- package/skills/incanto-assets.md +21 -0
- package/skills/incanto-behaviors-and-scripts.md +16 -0
- package/skills/incanto-editor.md +17 -1
- package/skills/incanto-gameplay-behaviors.md +6 -0
- package/skills/incanto-hud.md +16 -0
- package/skills/incanto-localization.md +132 -0
- package/skills/incanto-node-reference.md +33 -18
- package/skills/incanto-save-slots.md +152 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/PROJECT/Context.md +16 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/village.scene.json +25 -3
- package/editor/assets/index-BYCso8Bf.js +0 -10696
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-CMlKFT0C.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -325,6 +325,9 @@
|
|
|
325
325
|
{
|
|
326
326
|
"$ref": "#/$defs/UiImage"
|
|
327
327
|
},
|
|
328
|
+
{
|
|
329
|
+
"$ref": "#/$defs/UiLanguageSelect"
|
|
330
|
+
},
|
|
328
331
|
{
|
|
329
332
|
"$ref": "#/$defs/UiPanel"
|
|
330
333
|
},
|
|
@@ -1202,6 +1205,7 @@
|
|
|
1202
1205
|
},
|
|
1203
1206
|
"target": {
|
|
1204
1207
|
"type": "string",
|
|
1208
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
1205
1209
|
"default": ""
|
|
1206
1210
|
},
|
|
1207
1211
|
"bone": {
|
|
@@ -1308,6 +1312,7 @@
|
|
|
1308
1312
|
},
|
|
1309
1313
|
"target": {
|
|
1310
1314
|
"type": "string",
|
|
1315
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
1311
1316
|
"default": ""
|
|
1312
1317
|
},
|
|
1313
1318
|
"bone": {
|
|
@@ -1316,6 +1321,7 @@
|
|
|
1316
1321
|
},
|
|
1317
1322
|
"lookAt": {
|
|
1318
1323
|
"type": "string",
|
|
1324
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
1319
1325
|
"default": ""
|
|
1320
1326
|
},
|
|
1321
1327
|
"maxAngleDeg": {
|
|
@@ -1423,6 +1429,7 @@
|
|
|
1423
1429
|
},
|
|
1424
1430
|
"follow": {
|
|
1425
1431
|
"type": "string",
|
|
1432
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
1426
1433
|
"default": ""
|
|
1427
1434
|
},
|
|
1428
1435
|
"smoothing": {
|
|
@@ -2076,6 +2083,7 @@
|
|
|
2076
2083
|
},
|
|
2077
2084
|
"skinPath": {
|
|
2078
2085
|
"type": "string",
|
|
2086
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
2079
2087
|
"default": "../Skin"
|
|
2080
2088
|
},
|
|
2081
2089
|
"skinYawOffset": {
|
|
@@ -2469,6 +2477,7 @@
|
|
|
2469
2477
|
},
|
|
2470
2478
|
"terrain": {
|
|
2471
2479
|
"type": "string",
|
|
2480
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
2472
2481
|
"default": ""
|
|
2473
2482
|
}
|
|
2474
2483
|
},
|
|
@@ -2663,6 +2672,7 @@
|
|
|
2663
2672
|
},
|
|
2664
2673
|
"terrain": {
|
|
2665
2674
|
"type": "string",
|
|
2675
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
2666
2676
|
"default": ""
|
|
2667
2677
|
}
|
|
2668
2678
|
},
|
|
@@ -2956,6 +2966,7 @@
|
|
|
2956
2966
|
},
|
|
2957
2967
|
"target": {
|
|
2958
2968
|
"type": "string",
|
|
2969
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
2959
2970
|
"default": ""
|
|
2960
2971
|
},
|
|
2961
2972
|
"anchor": {
|
|
@@ -3093,6 +3104,7 @@
|
|
|
3093
3104
|
},
|
|
3094
3105
|
"target": {
|
|
3095
3106
|
"type": "string",
|
|
3107
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
3096
3108
|
"default": ""
|
|
3097
3109
|
},
|
|
3098
3110
|
"anchor": {
|
|
@@ -4873,6 +4885,7 @@
|
|
|
4873
4885
|
},
|
|
4874
4886
|
"terrain": {
|
|
4875
4887
|
"type": "string",
|
|
4888
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
4876
4889
|
"default": ""
|
|
4877
4890
|
},
|
|
4878
4891
|
"carve": {
|
|
@@ -5994,6 +6007,7 @@
|
|
|
5994
6007
|
},
|
|
5995
6008
|
"terrain": {
|
|
5996
6009
|
"type": "string",
|
|
6010
|
+
"description": "A node path: '%UniqueName', '/Absolute/From/Root', or relative to this node ('../Skin').",
|
|
5997
6011
|
"default": ""
|
|
5998
6012
|
}
|
|
5999
6013
|
},
|
|
@@ -6609,6 +6623,101 @@
|
|
|
6609
6623
|
},
|
|
6610
6624
|
"required": ["name", "type"]
|
|
6611
6625
|
},
|
|
6626
|
+
"UiLanguageSelect": {
|
|
6627
|
+
"type": "object",
|
|
6628
|
+
"x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped", "changed"],
|
|
6629
|
+
"properties": {
|
|
6630
|
+
"name": {
|
|
6631
|
+
"type": "string"
|
|
6632
|
+
},
|
|
6633
|
+
"uid": {
|
|
6634
|
+
"type": "string"
|
|
6635
|
+
},
|
|
6636
|
+
"type": {
|
|
6637
|
+
"const": "UiLanguageSelect"
|
|
6638
|
+
},
|
|
6639
|
+
"groups": {
|
|
6640
|
+
"type": "array",
|
|
6641
|
+
"items": {
|
|
6642
|
+
"type": "string"
|
|
6643
|
+
}
|
|
6644
|
+
},
|
|
6645
|
+
"tags": {
|
|
6646
|
+
"type": "object"
|
|
6647
|
+
},
|
|
6648
|
+
"props": {
|
|
6649
|
+
"type": "object",
|
|
6650
|
+
"properties": {
|
|
6651
|
+
"anchor": {
|
|
6652
|
+
"type": "string",
|
|
6653
|
+
"enum": [
|
|
6654
|
+
"topLeft",
|
|
6655
|
+
"top",
|
|
6656
|
+
"topRight",
|
|
6657
|
+
"left",
|
|
6658
|
+
"center",
|
|
6659
|
+
"right",
|
|
6660
|
+
"bottomLeft",
|
|
6661
|
+
"bottom",
|
|
6662
|
+
"bottomRight"
|
|
6663
|
+
],
|
|
6664
|
+
"default": "topLeft"
|
|
6665
|
+
},
|
|
6666
|
+
"visible": {
|
|
6667
|
+
"type": "boolean",
|
|
6668
|
+
"default": true
|
|
6669
|
+
},
|
|
6670
|
+
"focusable": {
|
|
6671
|
+
"type": "boolean",
|
|
6672
|
+
"default": true
|
|
6673
|
+
},
|
|
6674
|
+
"draggable": {
|
|
6675
|
+
"type": "boolean",
|
|
6676
|
+
"default": false
|
|
6677
|
+
},
|
|
6678
|
+
"dropTarget": {
|
|
6679
|
+
"type": "boolean",
|
|
6680
|
+
"default": false
|
|
6681
|
+
},
|
|
6682
|
+
"label": {
|
|
6683
|
+
"type": "string",
|
|
6684
|
+
"default": "Language"
|
|
6685
|
+
},
|
|
6686
|
+
"options": {
|
|
6687
|
+
"type": "string",
|
|
6688
|
+
"default": ""
|
|
6689
|
+
},
|
|
6690
|
+
"value": {
|
|
6691
|
+
"type": "string",
|
|
6692
|
+
"default": ""
|
|
6693
|
+
}
|
|
6694
|
+
},
|
|
6695
|
+
"additionalProperties": false
|
|
6696
|
+
},
|
|
6697
|
+
"script": {
|
|
6698
|
+
"type": "object",
|
|
6699
|
+
"properties": {
|
|
6700
|
+
"name": {
|
|
6701
|
+
"type": "string"
|
|
6702
|
+
},
|
|
6703
|
+
"props": {
|
|
6704
|
+
"type": "object"
|
|
6705
|
+
}
|
|
6706
|
+
},
|
|
6707
|
+
"required": ["name"]
|
|
6708
|
+
},
|
|
6709
|
+
"network": {
|
|
6710
|
+
"type": "object"
|
|
6711
|
+
},
|
|
6712
|
+
"children": {
|
|
6713
|
+
"type": "array",
|
|
6714
|
+
"items": {
|
|
6715
|
+
"$ref": "#/$defs/node"
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
},
|
|
6719
|
+
"required": ["name", "type"]
|
|
6720
|
+
},
|
|
6612
6721
|
"UiPanel": {
|
|
6613
6722
|
"type": "object",
|
|
6614
6723
|
"x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped"],
|
package/skills/incanto-assets.md
CHANGED
|
@@ -129,3 +129,24 @@ scene built that way stays plain JSON you can also hand-write.
|
|
|
129
129
|
|
|
130
130
|
Swap in real art later by changing ONLY the `assets{}` entry — node props
|
|
131
131
|
stay untouched.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## Textures are shared automatically (3D)
|
|
135
|
+
|
|
136
|
+
A hundred `Sprite3D`s pointing at one atlas cost **one** fetch, one decode and
|
|
137
|
+
one GPU upload. The renderer's asset store keys textures by URL plus their
|
|
138
|
+
sampler settings, so you never need to hoist a texture yourself or worry that
|
|
139
|
+
spawning enemies re-downloads their sheet.
|
|
140
|
+
|
|
141
|
+
Two consequences worth knowing:
|
|
142
|
+
|
|
143
|
+
- **Do not mutate a texture you got from a node.** `Sprite3D` and `Terrain3D`
|
|
144
|
+
hold the shared master. The two nodes with per-node UV state
|
|
145
|
+
(`AnimatedSprite3D`'s frame window, `MeshInstance3D`'s `material.repeat`) get
|
|
146
|
+
a private clone automatically — you do not have to ask for it.
|
|
147
|
+
- **`pixelArt: true` also turns mipmaps off**, which is what makes pixel art stay
|
|
148
|
+
crisp at distance instead of blurring into mud.
|
|
149
|
+
|
|
150
|
+
A texture that 404s now shows up in `game.assetErrors()` alongside models, by the
|
|
151
|
+
URL you wrote — so "why is my sprite invisible" is answerable without opening the
|
|
152
|
+
network tab.
|
|
@@ -38,6 +38,22 @@ class CoinCounter extends Behavior {
|
|
|
38
38
|
registerBehavior('CoinCounter', CoinCounter); // EXPLICIT — before loadScene
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
**A behavior that holds progress should be able to save it.** `serialize()` /
|
|
42
|
+
`deserialize(data)` are two more optional hooks in the same list, and they are
|
|
43
|
+
what makes "continue where you left off" possible — see
|
|
44
|
+
`incanto-save-slots.md`. Save only what a fresh `onReady` could not recreate.
|
|
45
|
+
|
|
46
|
+
**A prop that holds a node path must say so.** Mark it `nodePath: true` and the
|
|
47
|
+
editor rewrites it when the target is renamed; leave it off and the rename
|
|
48
|
+
silently breaks the link (`getNodeOrNull` returns null, nothing throws).
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
static readonly props = {
|
|
52
|
+
target: { default: '', nodePath: true }, // fed to getNode/getNodeOrNull
|
|
53
|
+
damage: { default: 10 },
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
41
57
|
## The three-artifact contract (keep them in sync!)
|
|
42
58
|
|
|
43
59
|
1. scene JSON `"script": {"name": "CoinCounter"}`
|
package/skills/incanto-editor.md
CHANGED
|
@@ -81,9 +81,25 @@ Opens a local page (default `http://127.0.0.1:5179/`) with three panes:
|
|
|
81
81
|
CharacterBody2D) are ROLLED BACK entirely with the error in the banner; the
|
|
82
82
|
tree never shows a state the engine would reject. Right-click for
|
|
83
83
|
duplicate / rename (or double-click the name) / cut / copy / paste-as-child /
|
|
84
|
-
delete — all act on the multi-selection.
|
|
84
|
+
delete — all act on the multi-selection. **Rename REPAIRS references**: every
|
|
85
|
+
`connections[].from/to` and every node-path prop pointing at the node (or into
|
|
86
|
+
its subtree) is rewritten in the same edit, across all three path forms
|
|
87
|
+
(`%Unique`, `/root/…`, relative `../Skin`), and the editor reports what it
|
|
88
|
+
changed. A prop is rewritten only if its type declares `nodePath: true`, so a
|
|
89
|
+
text prop that merely reads "Player" is never touched. `+` adds a child of any registered
|
|
85
90
|
type, `✕` deletes the selection. Selecting the ⚙ scene row edits the header
|
|
86
91
|
(dimension, gravity with real inputs, environment/input/assets/multiplayer).
|
|
92
|
+
- **CONNECTIONS on the selected node** — the inspector's last section shows what
|
|
93
|
+
the node **emits** and what it **receives**, each row being signal → target →
|
|
94
|
+
handler with a ✕ to remove and `+ connect` to add. Signals come from the node
|
|
95
|
+
type merged with its behavior's `static signals`; the target picker lists every
|
|
96
|
+
node in the scene; the handler is a dropdown of real methods when the target
|
|
97
|
+
has no script, and free text when it does (those handlers live in your
|
|
98
|
+
TypeScript, which the editor never loads). An end that no longer resolves is
|
|
99
|
+
marked red with the reason. For what a row cannot express — `filter`, `once`,
|
|
100
|
+
bound args — the scene header still has `connections` as raw JSON.
|
|
101
|
+
**Validation now runs WITH connections**: the editor used to strip them before
|
|
102
|
+
loading, so it reported green for a scene the game hard-fails to open.
|
|
87
103
|
- **Viewport with DIRECT MANIPULATION** — a mode toolbar (top left) + the
|
|
88
104
|
Unity/Godot keys: **W move · E rotate · R scale** (active mode highlighted).
|
|
89
105
|
A collider-visibility toggle sits beside the mode tools, and it shows the
|
|
@@ -58,6 +58,12 @@ Two kinds of node path resolve from DIFFERENT origins — mixing them up is the
|
|
|
58
58
|
enemy (a child of the Spawner) reaches the player with the ABSOLUTE
|
|
59
59
|
`/root/Player`, never a bare `Player` (which would look under the enemy).
|
|
60
60
|
|
|
61
|
+
Renaming a node in the editor now REWRITES both kinds for you (and reports what
|
|
62
|
+
it changed), so the paths above stay valid across a rename. Hand-edited JSON
|
|
63
|
+
still has to be kept in sync yourself — `bunx incanto-check` catches the
|
|
64
|
+
connections, but a behavior prop pointing at a name that no longer exists
|
|
65
|
+
resolves to null in silence.
|
|
66
|
+
|
|
61
67
|
**Never write `/root/<RootName>/...`.** If your root node is named `Game`, the
|
|
62
68
|
path is `/root/Player` — NOT `/root/Game/Player`: `/root/` already *is* the
|
|
63
69
|
`Game` root, so `/root/Game/...` double-counts it and dangles at load. Likewise
|
package/skills/incanto-hud.md
CHANGED
|
@@ -177,3 +177,19 @@ A drop on a CHILD of a slot counts as a drop on the slot (the cursor lands on th
|
|
|
177
177
|
icon inside it, which is the normal case), a drop on nothing cancels, and a
|
|
178
178
|
widget never drops onto itself.
|
|
179
179
|
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
## More than one language
|
|
183
|
+
|
|
184
|
+
Any text prop here can name a translation key instead of a literal:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{ "name": "Score", "type": "UiText", "props": { "text": "@t:hud.score" } }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Strings live in the scene header's `strings` block, English is the base, and a
|
|
191
|
+
key a locale omits falls back to English silently — which is the RIGHT answer
|
|
192
|
+
whenever the English term is more precise or the translation would not fit.
|
|
193
|
+
`UiLanguageSelect` is the picker, already wired.
|
|
194
|
+
|
|
195
|
+
Read `incanto-localization.md` before adding a second language.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: incanto-localization
|
|
3
|
+
description: Ship a game in more than one language: a scene-header `strings` table, `"@t:key"` text props, `engine.t()`, and a ready-made UiLanguageSelect that switches live and persists. English is the base — a key a locale omits falls back to it silently, on purpose. Use whenever a game needs a language other than English, or a language setting.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Localization — English base, other languages on top
|
|
7
|
+
|
|
8
|
+
Ship a game in more than one language without a second build, a second scene, or
|
|
9
|
+
a page reload.
|
|
10
|
+
|
|
11
|
+
**English is the base and the default.** Every other locale is a partial overlay:
|
|
12
|
+
anything it does not translate falls back to English, silently.
|
|
13
|
+
|
|
14
|
+
## The rule that matters most
|
|
15
|
+
|
|
16
|
+
> When a translation is ambiguous, when the English term is the more precise one,
|
|
17
|
+
> or when the translation runs so much longer than the English that it breaks the
|
|
18
|
+
> layout — **ship the English.**
|
|
19
|
+
|
|
20
|
+
Leaving a key untranslated is a **decision**, not a gap to fill. `COMBO`,
|
|
21
|
+
`BOSS`, `LV.`, `HP`, `x1.5` are usually clearer in English to players in every
|
|
22
|
+
language, and a "Continue to the next chapter" that becomes three lines in a
|
|
23
|
+
button will break your menu. Omit the key and the English appears. Nothing warns,
|
|
24
|
+
nothing marks it, nothing logs.
|
|
25
|
+
|
|
26
|
+
The only mistake worth reporting is a key **nothing** declares — a typo, which
|
|
27
|
+
renders raw on screen. `bunx incanto-check` tells you at author time.
|
|
28
|
+
|
|
29
|
+
## Declaring strings
|
|
30
|
+
|
|
31
|
+
One `strings` block in the scene header, locale first:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"format": 1, "type": "scene", "name": "Menu",
|
|
36
|
+
"strings": {
|
|
37
|
+
"en": {
|
|
38
|
+
"menu.start": "Start Game",
|
|
39
|
+
"menu.options": "Options",
|
|
40
|
+
"settings.language": "Language",
|
|
41
|
+
"hud.wave": "Wave {n}",
|
|
42
|
+
"hud.combo": "COMBO"
|
|
43
|
+
},
|
|
44
|
+
"ko": {
|
|
45
|
+
"menu.start": "게임 시작",
|
|
46
|
+
"menu.options": "설정",
|
|
47
|
+
"settings.language": "언어",
|
|
48
|
+
"hud.wave": "{n} 웨이브"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"root": { "...": "..." }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`hud.combo` has no Korean entry on purpose — "COMBO" is the term players already
|
|
56
|
+
read. It shows as `COMBO` in both languages, and that is correct.
|
|
57
|
+
|
|
58
|
+
Tables **merge** across scenes: put your shared UI strings in the scene the game
|
|
59
|
+
boots from, and a level that adds three lines of its own keeps them.
|
|
60
|
+
|
|
61
|
+
## Using them
|
|
62
|
+
|
|
63
|
+
A text prop becomes translatable by naming a key with `@t:` — the same shape as
|
|
64
|
+
the `"$assetKey"` references you already write:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{ "name": "Start", "type": "UiButton", "props": { "text": "@t:menu.start" } }
|
|
68
|
+
{ "name": "Wave", "type": "UiText", "props": { "text": "@t:hud.wave" } }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Works on every text-bearing widget: `UiText.text`, `UiButton.text`,
|
|
72
|
+
`UiBar.label`, `UiSelect.label`, `UiBanner.show()`, and `UiDialogue` lines,
|
|
73
|
+
speakers and choices.
|
|
74
|
+
|
|
75
|
+
From a behavior, `engine.t(key, params)`:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
banner.show(this.engine.t('hud.wave', { n: this.wave }));
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`{n}` slots are filled from `params`; a slot with no matching param is left
|
|
82
|
+
alone rather than blanked.
|
|
83
|
+
|
|
84
|
+
## The language picker
|
|
85
|
+
|
|
86
|
+
One node. Do not build your own.
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{ "name": "Language", "type": "UiLanguageSelect",
|
|
90
|
+
"props": { "label": "@t:settings.language" } }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Its options are the locales your scene declares — a game shipping only English
|
|
94
|
+
shows only English — each labeled with its own endonym (`한국어`, not `Korean`),
|
|
95
|
+
because a player who cannot read the language on screen still has to find theirs.
|
|
96
|
+
Picking one switches the game **live** and persists the choice through
|
|
97
|
+
`engine.settings`, so the next visit opens in it.
|
|
98
|
+
|
|
99
|
+
## What NOT to localize
|
|
100
|
+
|
|
101
|
+
- **Values, not labels.** `UiSelect.options` are values the game compares
|
|
102
|
+
against (`"low,medium,high"`); translating them breaks the comparison.
|
|
103
|
+
- **Node names, group names, asset keys, signal names, action names.** These are
|
|
104
|
+
identifiers.
|
|
105
|
+
- **Anything a behavior parses.** If code does `if (value === 'start')`, that
|
|
106
|
+
string is an identifier wearing a label's clothes.
|
|
107
|
+
|
|
108
|
+
## Verifying
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
bunx incanto-check src/scenes/menu.scene.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Reports any `@t:` key that no locale declares. It says nothing about a key one
|
|
115
|
+
locale omits — that is the design, not a warning.
|
|
116
|
+
|
|
117
|
+
To check a language actually renders, set it and read the frame:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
game.engine.locale.locale = 'ko';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Switching takes effect on the **next frame** — nothing to reload, nothing to
|
|
124
|
+
invalidate. Widgets re-read their text every frame, which is what makes this
|
|
125
|
+
work.
|
|
126
|
+
|
|
127
|
+
## Fonts
|
|
128
|
+
|
|
129
|
+
The engine's HUD uses the platform font stack. On a machine with no CJK face
|
|
130
|
+
installed, Korean renders as boxes — that is the operating system, not the
|
|
131
|
+
engine. If you ship Korean to an audience you do not control, add a webfont in
|
|
132
|
+
your own page CSS and set it on the HUD layer.
|
|
@@ -145,7 +145,7 @@ Signals: `finished`
|
|
|
145
145
|
| `renderOrder` | `0` | number |
|
|
146
146
|
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
147
147
|
| `snapToGround` | `null` | null |
|
|
148
|
-
| `target` | `""` |
|
|
148
|
+
| `target` | `""` | node path |
|
|
149
149
|
| `bone` | `""` | string |
|
|
150
150
|
|
|
151
151
|
## `BoneLookAt3D` — `incanto/3d`
|
|
@@ -160,9 +160,9 @@ Signals: `finished`
|
|
|
160
160
|
| `renderOrder` | `0` | number |
|
|
161
161
|
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
162
162
|
| `snapToGround` | `null` | null |
|
|
163
|
-
| `target` | `""` |
|
|
163
|
+
| `target` | `""` | node path |
|
|
164
164
|
| `bone` | `"Head"` | string |
|
|
165
|
-
| `lookAt` | `""` |
|
|
165
|
+
| `lookAt` | `""` | node path |
|
|
166
166
|
| `maxAngleDeg` | `75` | number |
|
|
167
167
|
| `weight` | `0.85` | number |
|
|
168
168
|
| `forwardAxis` | `"+z"` | one of: `+x` `-x` `+y` `-y` `+z` `-z` |
|
|
@@ -178,7 +178,7 @@ Signals: `finished`
|
|
|
178
178
|
| `renderOrder` | `0` | number |
|
|
179
179
|
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
180
180
|
| `visible` | `true` | boolean |
|
|
181
|
-
| `follow` | `""` |
|
|
181
|
+
| `follow` | `""` | node path |
|
|
182
182
|
| `smoothing` | `0` | number |
|
|
183
183
|
| `zoom` | `1` | number |
|
|
184
184
|
| `limits` | `[]` | array |
|
|
@@ -289,7 +289,7 @@ Signals: `movementStateChanged(state)`
|
|
|
289
289
|
| `moveAction` | `"move"` | string |
|
|
290
290
|
| `jumpAction` | `"jump"` | string |
|
|
291
291
|
| `sprintAction` | `"sprint"` | string |
|
|
292
|
-
| `skinPath` | `"../Skin"` |
|
|
292
|
+
| `skinPath` | `"../Skin"` | node path |
|
|
293
293
|
| `skinYawOffset` | `0` | number |
|
|
294
294
|
| `animations` | `{}` | object |
|
|
295
295
|
|
|
@@ -352,7 +352,7 @@ Signals: `movementStateChanged(state)`
|
|
|
352
352
|
| `sway` | `0.5` | number |
|
|
353
353
|
| `drape` | `null` | null |
|
|
354
354
|
| `avoidWater` | `true` | boolean |
|
|
355
|
-
| `terrain` | `""` |
|
|
355
|
+
| `terrain` | `""` | node path |
|
|
356
356
|
|
|
357
357
|
## `Foliage3D` — `incanto/3d`
|
|
358
358
|
|
|
@@ -386,7 +386,7 @@ Signals: `movementStateChanged(state)`
|
|
|
386
386
|
| `seed` | `1` | number |
|
|
387
387
|
| `drape` | `null` | null |
|
|
388
388
|
| `avoidWater` | `true` | boolean |
|
|
389
|
-
| `terrain` | `""` |
|
|
389
|
+
| `terrain` | `""` | node path |
|
|
390
390
|
|
|
391
391
|
## `HudLayer` — `incanto`
|
|
392
392
|
|
|
@@ -428,7 +428,7 @@ Signals: `movementStateChanged(state)`
|
|
|
428
428
|
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
429
429
|
| `visible` | `true` | boolean |
|
|
430
430
|
| `type` | `"revolute"` | one of: `fixed` `revolute` `rope` `spring` |
|
|
431
|
-
| `target` | `""` |
|
|
431
|
+
| `target` | `""` | node path |
|
|
432
432
|
| `anchor` | `[0,0]` | array |
|
|
433
433
|
| `targetAnchor` | `[0,0]` | array |
|
|
434
434
|
| `length` | `0` | number |
|
|
@@ -448,7 +448,7 @@ Signals: `movementStateChanged(state)`
|
|
|
448
448
|
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
449
449
|
| `snapToGround` | `null` | null |
|
|
450
450
|
| `type` | `"spherical"` | one of: `fixed` `spherical` `rope` `spring` |
|
|
451
|
-
| `target` | `""` |
|
|
451
|
+
| `target` | `""` | node path |
|
|
452
452
|
| `anchor` | `[0,0,0]` | array |
|
|
453
453
|
| `targetAnchor` | `[0,0,0]` | array |
|
|
454
454
|
| `length` | `0` | number |
|
|
@@ -731,7 +731,7 @@ Signals: `triggerEnter(other)` · `triggerExit(other)`
|
|
|
731
731
|
| `sunDirection` | `[0.5,0.8,0.3]` | array |
|
|
732
732
|
| `sunColor` | `"#fff6e0"` | string |
|
|
733
733
|
| `sunIntensity` | `1` | number |
|
|
734
|
-
| `terrain` | `""` |
|
|
734
|
+
| `terrain` | `""` | node path |
|
|
735
735
|
| `carve` | `true` | boolean |
|
|
736
736
|
| `flowForce` | `1` | number |
|
|
737
737
|
| `spray` | `1` | number |
|
|
@@ -910,7 +910,7 @@ Signals: `timeout`
|
|
|
910
910
|
| `leafFadeEnd` | `0` | number |
|
|
911
911
|
| `leafShadows` | `true` | boolean |
|
|
912
912
|
| `drape` | `null` | null |
|
|
913
|
-
| `terrain` | `""` |
|
|
913
|
+
| `terrain` | `""` | node path |
|
|
914
914
|
|
|
915
915
|
## `UILayer` — `incanto/2d`
|
|
916
916
|
|
|
@@ -1002,6 +1002,21 @@ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `lineSh
|
|
|
1002
1002
|
|
|
1003
1003
|
Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped`
|
|
1004
1004
|
|
|
1005
|
+
## `UiLanguageSelect` — `incanto`
|
|
1006
|
+
|
|
1007
|
+
| Prop | Default | Kind |
|
|
1008
|
+
|---|---|---|
|
|
1009
|
+
| `anchor` | `"topLeft"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
|
|
1010
|
+
| `visible` | `true` | boolean |
|
|
1011
|
+
| `focusable` | `true` | boolean |
|
|
1012
|
+
| `draggable` | `false` | boolean |
|
|
1013
|
+
| `dropTarget` | `false` | boolean |
|
|
1014
|
+
| `label` | `"Language"` | string |
|
|
1015
|
+
| `options` | `""` | string |
|
|
1016
|
+
| `value` | `""` | string |
|
|
1017
|
+
|
|
1018
|
+
Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `changed`
|
|
1019
|
+
|
|
1005
1020
|
## `UiPanel` — `incanto`
|
|
1006
1021
|
|
|
1007
1022
|
| Prop | Default | Kind |
|
|
@@ -1173,7 +1188,7 @@ wire their signals through scene `connections`. Full guide: `incanto-gameplay-be
|
|
|
1173
1188
|
|
|
1174
1189
|
| Prop | Default | Kind |
|
|
1175
1190
|
|---|---|---|
|
|
1176
|
-
| `water` | `""` |
|
|
1191
|
+
| `water` | `""` | node path |
|
|
1177
1192
|
| `draft` | `0.35` | number |
|
|
1178
1193
|
| `stiffness` | `3` | number |
|
|
1179
1194
|
| `damping` | `3.5` | number |
|
|
@@ -1194,7 +1209,7 @@ Signals: `submerged` · `surfaced`
|
|
|
1194
1209
|
|
|
1195
1210
|
| Prop | Default | Kind |
|
|
1196
1211
|
|---|---|---|
|
|
1197
|
-
| `target` | `""` |
|
|
1212
|
+
| `target` | `""` | node path |
|
|
1198
1213
|
| `speed` | `60` | number |
|
|
1199
1214
|
| `stopRange` | `0` | number |
|
|
1200
1215
|
| `loseRange` | `0` | number |
|
|
@@ -1248,7 +1263,7 @@ Signals: `dayPhaseChanged`
|
|
|
1248
1263
|
|
|
1249
1264
|
| Prop | Default | Kind |
|
|
1250
1265
|
|---|---|---|
|
|
1251
|
-
| `target` | `""` |
|
|
1266
|
+
| `target` | `""` | node path |
|
|
1252
1267
|
| `offset` | `[]` | array |
|
|
1253
1268
|
| `smoothing` | `0` | number |
|
|
1254
1269
|
| `deadzone` | `0` | number |
|
|
@@ -1259,7 +1274,7 @@ Signals: `dayPhaseChanged`
|
|
|
1259
1274
|
|---|---|---|
|
|
1260
1275
|
| `restartAction` | `"restart"` | string |
|
|
1261
1276
|
| `freezeOnEnd` | `true` | boolean |
|
|
1262
|
-
| `bannerPath` | `"%Banner"` |
|
|
1277
|
+
| `bannerPath` | `"%Banner"` | node path |
|
|
1263
1278
|
|
|
1264
1279
|
Signals: `flowChanged`
|
|
1265
1280
|
|
|
@@ -1366,7 +1381,7 @@ Signals: `scoreChanged(score)` · `won` · `lost` · `lifeLost(lives)`
|
|
|
1366
1381
|
|
|
1367
1382
|
| Prop | Default | Kind |
|
|
1368
1383
|
|---|---|---|
|
|
1369
|
-
| `prefab` | `""` |
|
|
1384
|
+
| `prefab` | `""` | node path |
|
|
1370
1385
|
| `interval` | `1` | number |
|
|
1371
1386
|
| `max` | `0` | number |
|
|
1372
1387
|
| `at` | `[]` | array |
|
|
@@ -1396,14 +1411,14 @@ Signals: `waveStarted(index)` · `waveCleared(index)` · `allCleared`
|
|
|
1396
1411
|
|
|
1397
1412
|
| Prop | Default | Kind |
|
|
1398
1413
|
|---|---|---|
|
|
1399
|
-
| `aggroTarget` | `""` |
|
|
1414
|
+
| `aggroTarget` | `""` | node path |
|
|
1400
1415
|
| `aggroRange` | `12` | number |
|
|
1401
1416
|
| `deAggroRange` | `0` | number |
|
|
1402
1417
|
| `chaseSpeed` | `4` | number |
|
|
1403
1418
|
| `wanderSpeed` | `1.4` | number |
|
|
1404
1419
|
| `wanderRadius` | `8` | number |
|
|
1405
1420
|
| `wanderChangeEvery` | `3` | number |
|
|
1406
|
-
| `goalTarget` | `""` |
|
|
1421
|
+
| `goalTarget` | `""` | node path |
|
|
1407
1422
|
| `stopRange` | `1.2` | number |
|
|
1408
1423
|
| `moveParent` | `false` | boolean |
|
|
1409
1424
|
|