incanto 0.36.2 → 0.38.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.
Files changed (57) hide show
  1. package/bin/incanto-feel.mjs +93 -0
  2. package/bin/incanto-playtest.mjs +136 -0
  3. package/dist/2d.d.ts +2 -2
  4. package/dist/2d.js +3 -3
  5. package/dist/3d.d.ts +44 -3
  6. package/dist/3d.js +4 -32
  7. package/dist/{behavior-DibCwrW7.d.ts → behavior-B5PJ32eu.d.ts} +106 -6
  8. package/dist/{create-game-D-StzrTj.js → create-game-C4t5gVhc.js} +5 -5
  9. package/dist/{create-game-DnOu2aAa.js → create-game-DqY2lMBc.js} +783 -689
  10. package/dist/debug.d.ts +1 -1
  11. package/dist/{duplicate-Cvb1BSca.js → duplicate-CRtihGmC.js} +1 -1
  12. package/dist/editor.js +21 -0
  13. package/dist/{environment-presets-fK9oyrrR.js → environment-presets-C0Axpfth.js} +75 -9
  14. package/dist/{gameplay-C0MUMSak.js → gameplay-CsJDUQh_.js} +2 -2
  15. package/dist/gameplay.d.ts +1 -1
  16. package/dist/gameplay.js +1 -1
  17. package/dist/index.d.ts +4 -50
  18. package/dist/index.js +5 -75
  19. package/dist/{loader-BqigZsfF.d.ts → loader-DSMdqasu.d.ts} +1 -1
  20. package/dist/{loader-DAZlgqeC.js → loader-r49nDwB4.js} +15 -0
  21. package/dist/net.d.ts +1 -1
  22. package/dist/net.js +3 -3
  23. package/dist/{pathfinding-B3QtdhvZ.d.ts → pathfinding-BrE5Uec6.d.ts} +1 -1
  24. package/dist/{physics-2d-B4v39hca.js → physics-2d-OfKb0PV_.js} +2 -2
  25. package/dist/{physics-3d-DFJVMYET.js → physics-3d-C8242nXr.js} +3 -3
  26. package/dist/react.d.ts +1 -1
  27. package/dist/react.js +1 -1
  28. package/dist/{register-DXwtIVqP.js → register-B4RRQbyq.js} +2 -2
  29. package/dist/{register-BHAwM4bK.js → register-Dm7nrd-E.js} +322 -34
  30. package/dist/{register-COGCNitr.js → register-DnB9m7Rl.js} +2 -2
  31. package/dist/replay-Cxrr-ApH.d.ts +86 -0
  32. package/dist/{audit-D7F3n3Nt.js → replay-DH0UOuZ-.js} +72 -2
  33. package/dist/test-CoDPWx-m.js +1404 -0
  34. package/dist/test.d.ts +113 -4
  35. package/dist/test.js +3 -3
  36. package/dist/vite.js +1 -1
  37. package/editor/assets/{agent8-DMvBVhe4.js → agent8-BtIlblPm.js} +1 -1
  38. package/editor/assets/{debug-BgAq55oC.js → debug-BvTmHXI7.js} +1 -1
  39. package/editor/assets/{index-Cy_QsKbh.js → index-BS01WWgM.js} +91 -91
  40. package/editor/index.html +1 -1
  41. package/package.json +3 -1
  42. package/schemas/scene.schema.json +318 -0
  43. package/skills/incanto-3d-character.md +35 -0
  44. package/skills/incanto-building-2d-games.md +6 -0
  45. package/skills/incanto-building-3d-games.md +6 -0
  46. package/skills/incanto-game-feel.md +76 -0
  47. package/skills/incanto-node-reference.md +51 -0
  48. package/skills/incanto-performance.md +212 -0
  49. package/skills/incanto-playtesting.md +143 -0
  50. package/skills/incanto-verifying-your-game.md +41 -0
  51. package/templates-app/beacon-isle-3d/package.json +1 -1
  52. package/templates-app/tps-3d/package.json +1 -1
  53. package/templates-app/village-quest-3d/package.json +1 -1
  54. package/templates-app/village-quest-3d/src/village.scene.json +3 -1
  55. package/templates-app/village-quest-3d/verify.ts +55 -5
  56. package/dist/errors-DGRtWlSx.d.ts +0 -39
  57. package/dist/test-X_xE6Yay.js +0 -642
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-Cy_QsKbh.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-BS01WWgM.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.36.2",
3
+ "version": "0.38.0",
4
4
  "description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
5
5
  "keywords": [
6
6
  "game-engine",
@@ -95,6 +95,8 @@
95
95
  "incanto-assets": "bin/incanto-assets.mjs",
96
96
  "incanto-env": "bin/incanto-env.mjs",
97
97
  "incanto-play": "bin/incanto-play.mjs",
98
+ "incanto-playtest": "bin/incanto-playtest.mjs",
99
+ "incanto-feel": "bin/incanto-feel.mjs",
98
100
  "incanto-new": "bin/incanto-new.mjs"
99
101
  }
100
102
  }
@@ -343,6 +343,9 @@
343
343
  {
344
344
  "$ref": "#/$defs/UiDialogue"
345
345
  },
346
+ {
347
+ "$ref": "#/$defs/UiFrameCapSelect"
348
+ },
346
349
  {
347
350
  "$ref": "#/$defs/UiImage"
348
351
  },
@@ -352,6 +355,12 @@
352
355
  {
353
356
  "$ref": "#/$defs/UiPanel"
354
357
  },
358
+ {
359
+ "$ref": "#/$defs/UiQualitySelect"
360
+ },
361
+ {
362
+ "$ref": "#/$defs/UiRenderScaleSelect"
363
+ },
355
364
  {
356
365
  "$ref": "#/$defs/UiSelect"
357
366
  },
@@ -2054,6 +2063,30 @@
2054
2063
  "type": "number",
2055
2064
  "default": 1.2
2056
2065
  },
2066
+ "coyoteSeconds": {
2067
+ "type": "number",
2068
+ "default": 0
2069
+ },
2070
+ "jumpBufferSeconds": {
2071
+ "type": "number",
2072
+ "default": 0
2073
+ },
2074
+ "jumpCutMultiplier": {
2075
+ "type": "number",
2076
+ "default": 1
2077
+ },
2078
+ "maxJumps": {
2079
+ "type": "number",
2080
+ "default": 1
2081
+ },
2082
+ "airControl": {
2083
+ "type": "number",
2084
+ "default": 0.2
2085
+ },
2086
+ "fallGravity": {
2087
+ "type": "number",
2088
+ "default": 2.5
2089
+ },
2057
2090
  "floatHeight": {
2058
2091
  "type": "number",
2059
2092
  "default": 0.01
@@ -6536,6 +6569,101 @@
6536
6569
  },
6537
6570
  "required": ["name", "type"]
6538
6571
  },
6572
+ "UiFrameCapSelect": {
6573
+ "type": "object",
6574
+ "x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped", "changed"],
6575
+ "properties": {
6576
+ "name": {
6577
+ "type": "string"
6578
+ },
6579
+ "uid": {
6580
+ "type": "string"
6581
+ },
6582
+ "type": {
6583
+ "const": "UiFrameCapSelect"
6584
+ },
6585
+ "groups": {
6586
+ "type": "array",
6587
+ "items": {
6588
+ "type": "string"
6589
+ }
6590
+ },
6591
+ "tags": {
6592
+ "type": "object"
6593
+ },
6594
+ "props": {
6595
+ "type": "object",
6596
+ "properties": {
6597
+ "anchor": {
6598
+ "type": "string",
6599
+ "enum": [
6600
+ "topLeft",
6601
+ "top",
6602
+ "topRight",
6603
+ "left",
6604
+ "center",
6605
+ "right",
6606
+ "bottomLeft",
6607
+ "bottom",
6608
+ "bottomRight"
6609
+ ],
6610
+ "default": "topLeft"
6611
+ },
6612
+ "visible": {
6613
+ "type": "boolean",
6614
+ "default": true
6615
+ },
6616
+ "focusable": {
6617
+ "type": "boolean",
6618
+ "default": true
6619
+ },
6620
+ "draggable": {
6621
+ "type": "boolean",
6622
+ "default": false
6623
+ },
6624
+ "dropTarget": {
6625
+ "type": "boolean",
6626
+ "default": false
6627
+ },
6628
+ "label": {
6629
+ "type": "string",
6630
+ "default": "Frame rate"
6631
+ },
6632
+ "options": {
6633
+ "type": "string",
6634
+ "default": "30,60,120,0"
6635
+ },
6636
+ "value": {
6637
+ "type": "string",
6638
+ "default": ""
6639
+ }
6640
+ },
6641
+ "additionalProperties": false
6642
+ },
6643
+ "script": {
6644
+ "type": "object",
6645
+ "properties": {
6646
+ "name": {
6647
+ "type": "string"
6648
+ },
6649
+ "props": {
6650
+ "type": "object"
6651
+ }
6652
+ },
6653
+ "required": ["name"]
6654
+ },
6655
+ "network": {
6656
+ "type": "object"
6657
+ },
6658
+ "children": {
6659
+ "type": "array",
6660
+ "items": {
6661
+ "$ref": "#/$defs/node"
6662
+ }
6663
+ }
6664
+ },
6665
+ "required": ["name", "type"]
6666
+ },
6539
6667
  "UiImage": {
6540
6668
  "type": "object",
6541
6669
  "x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped"],
@@ -6859,6 +6987,196 @@
6859
6987
  },
6860
6988
  "required": ["name", "type"]
6861
6989
  },
6990
+ "UiQualitySelect": {
6991
+ "type": "object",
6992
+ "x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped", "changed"],
6993
+ "properties": {
6994
+ "name": {
6995
+ "type": "string"
6996
+ },
6997
+ "uid": {
6998
+ "type": "string"
6999
+ },
7000
+ "type": {
7001
+ "const": "UiQualitySelect"
7002
+ },
7003
+ "groups": {
7004
+ "type": "array",
7005
+ "items": {
7006
+ "type": "string"
7007
+ }
7008
+ },
7009
+ "tags": {
7010
+ "type": "object"
7011
+ },
7012
+ "props": {
7013
+ "type": "object",
7014
+ "properties": {
7015
+ "anchor": {
7016
+ "type": "string",
7017
+ "enum": [
7018
+ "topLeft",
7019
+ "top",
7020
+ "topRight",
7021
+ "left",
7022
+ "center",
7023
+ "right",
7024
+ "bottomLeft",
7025
+ "bottom",
7026
+ "bottomRight"
7027
+ ],
7028
+ "default": "topLeft"
7029
+ },
7030
+ "visible": {
7031
+ "type": "boolean",
7032
+ "default": true
7033
+ },
7034
+ "focusable": {
7035
+ "type": "boolean",
7036
+ "default": true
7037
+ },
7038
+ "draggable": {
7039
+ "type": "boolean",
7040
+ "default": false
7041
+ },
7042
+ "dropTarget": {
7043
+ "type": "boolean",
7044
+ "default": false
7045
+ },
7046
+ "label": {
7047
+ "type": "string",
7048
+ "default": "Quality"
7049
+ },
7050
+ "options": {
7051
+ "type": "string",
7052
+ "default": "low,medium,high"
7053
+ },
7054
+ "value": {
7055
+ "type": "string",
7056
+ "default": ""
7057
+ }
7058
+ },
7059
+ "additionalProperties": false
7060
+ },
7061
+ "script": {
7062
+ "type": "object",
7063
+ "properties": {
7064
+ "name": {
7065
+ "type": "string"
7066
+ },
7067
+ "props": {
7068
+ "type": "object"
7069
+ }
7070
+ },
7071
+ "required": ["name"]
7072
+ },
7073
+ "network": {
7074
+ "type": "object"
7075
+ },
7076
+ "children": {
7077
+ "type": "array",
7078
+ "items": {
7079
+ "$ref": "#/$defs/node"
7080
+ }
7081
+ }
7082
+ },
7083
+ "required": ["name", "type"]
7084
+ },
7085
+ "UiRenderScaleSelect": {
7086
+ "type": "object",
7087
+ "x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped", "changed"],
7088
+ "properties": {
7089
+ "name": {
7090
+ "type": "string"
7091
+ },
7092
+ "uid": {
7093
+ "type": "string"
7094
+ },
7095
+ "type": {
7096
+ "const": "UiRenderScaleSelect"
7097
+ },
7098
+ "groups": {
7099
+ "type": "array",
7100
+ "items": {
7101
+ "type": "string"
7102
+ }
7103
+ },
7104
+ "tags": {
7105
+ "type": "object"
7106
+ },
7107
+ "props": {
7108
+ "type": "object",
7109
+ "properties": {
7110
+ "anchor": {
7111
+ "type": "string",
7112
+ "enum": [
7113
+ "topLeft",
7114
+ "top",
7115
+ "topRight",
7116
+ "left",
7117
+ "center",
7118
+ "right",
7119
+ "bottomLeft",
7120
+ "bottom",
7121
+ "bottomRight"
7122
+ ],
7123
+ "default": "topLeft"
7124
+ },
7125
+ "visible": {
7126
+ "type": "boolean",
7127
+ "default": true
7128
+ },
7129
+ "focusable": {
7130
+ "type": "boolean",
7131
+ "default": true
7132
+ },
7133
+ "draggable": {
7134
+ "type": "boolean",
7135
+ "default": false
7136
+ },
7137
+ "dropTarget": {
7138
+ "type": "boolean",
7139
+ "default": false
7140
+ },
7141
+ "label": {
7142
+ "type": "string",
7143
+ "default": "Resolution"
7144
+ },
7145
+ "options": {
7146
+ "type": "string",
7147
+ "default": "0.5,0.75,1"
7148
+ },
7149
+ "value": {
7150
+ "type": "string",
7151
+ "default": ""
7152
+ }
7153
+ },
7154
+ "additionalProperties": false
7155
+ },
7156
+ "script": {
7157
+ "type": "object",
7158
+ "properties": {
7159
+ "name": {
7160
+ "type": "string"
7161
+ },
7162
+ "props": {
7163
+ "type": "object"
7164
+ }
7165
+ },
7166
+ "required": ["name"]
7167
+ },
7168
+ "network": {
7169
+ "type": "object"
7170
+ },
7171
+ "children": {
7172
+ "type": "array",
7173
+ "items": {
7174
+ "$ref": "#/$defs/node"
7175
+ }
7176
+ }
7177
+ },
7178
+ "required": ["name", "type"]
7179
+ },
6862
7180
  "UiSelect": {
6863
7181
  "type": "object",
6864
7182
  "x-signals": ["dragStarted", "dragCancelled", "droppedOn", "dropped", "changed"],
@@ -39,6 +39,41 @@ capsule BOTTOM `floatHeight` above the ground (5-ray probe). Author the Skin
39
39
  y-offset as `-(halfHeight + radius + floatHeight)` so the feet sit at the
40
40
  capsule bottom (the example templates do this).
41
41
 
42
+ ## Game feel — the props a jump needs to stop feeling broken
43
+
44
+ A jump that only fires while the ground ray says so feels BROKEN, and players do
45
+ not report it as "the coyote time is missing" — they report the game as
46
+ unresponsive. `CharacterController2D` got these in 0.33.0; the 3D controller
47
+ did not until now.
48
+
49
+ | prop | default | what it buys |
50
+ |---|---|---|
51
+ | `coyoteSeconds` | `0` | jump this long AFTER walking off a ledge. **The single biggest one** — try `0.12`. |
52
+ | `jumpBufferSeconds` | `0` | press jump this long BEFORE landing and still get it. Try `0.15`. |
53
+ | `jumpCutMultiplier` | `1` | release early and the rise is cut to this fraction. `0.45` = variable-height jump. |
54
+ | `maxJumps` | `1` | `2` = double jump. Extra jumps work in mid-air. |
55
+ | `airControl` | `0.2` | how much ground control you keep airborne (0 = committed, 1 = full). |
56
+ | `fallGravity` | `2.5` | gravity multiplier while falling. Higher = snappier arc. |
57
+
58
+ Every one defaults to OFF (`0` / `1`) or to the previous hard-coded constant, so
59
+ a scene that asks for nothing behaves exactly as before.
60
+
61
+ ```json
62
+ { "name": "Ctl", "type": "CharacterController3D",
63
+ "props": { "coyoteSeconds": 0.12, "jumpBufferSeconds": 0.15,
64
+ "jumpCutMultiplier": 0.45, "maxJumps": 2 } }
65
+ ```
66
+
67
+ **Jump reads the button EDGE.** Holding the jump key no longer re-jumps every
68
+ frame — that auto-hop was never intended and it made coyote time incoherent (a
69
+ held button would re-fire through the whole window).
70
+
71
+ **Two ground senses, deliberately.** `grounded` stays generous (slack for the
72
+ hover spring, so slopes and bumps do not flicker the animation state). The feel
73
+ props and the airborne animation use a stricter test: close to the support AND
74
+ not moving upward. Without the velocity term the check is one frame stale, which
75
+ at launch speed is ~6 cm — enough to still read as standing on the floor.
76
+
42
77
  ## Views
43
78
 
44
79
  | view | what it does | key props |
@@ -329,3 +329,9 @@ Wall moves need to know there IS a wall: `CharacterBody2D` now answers
329
329
  `isOnFloor()`. Before, the floor was the only surface a character could report,
330
330
  which is why a wall jump was not awkward to write but impossible.
331
331
 
332
+
333
+
334
+ **And then play it.** `bunx incanto-playtest src/game.scene.json` runs seeded
335
+ headless bot sessions and reports what could not be reached, which wires never
336
+ fired, and whether anything in the level can hurt the player. See
337
+ `incanto-playtesting.md`.
@@ -578,3 +578,9 @@ behind it), what lights the scene, and which colliders intersect. Then read
578
578
  `stats().errors` (something threw and got skipped) and `assetErrors()` (a model
579
579
  404'd). All four are silent failures otherwise — the screen just looks wrong,
580
580
  or empty, and nothing throws.
581
+
582
+
583
+ **And then play it.** `bunx incanto-playtest src/game.scene.json` runs seeded
584
+ headless bot sessions and reports what could not be reached, which wires never
585
+ fired, and whether anything in the level can hurt the player. See
586
+ `incanto-playtesting.md`.
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: incanto-game-feel
3
+ description: Measure what your controls actually feel like — bunx incanto-feel reports top speed, ramp and stop times, turnaround, jump apex and airtime, and the coyote/jump-buffer windows MEASURED by probing rather than read from the schema. Use when tuning a character, or when a game "feels off" and you cannot see why.
4
+ ---
5
+
6
+ # Game feel, as numbers
7
+
8
+ `capture()` and `framing()` are snapshots. Feel lives on the **time axis**.
9
+
10
+ ```bash
11
+ bunx incanto-feel src/game.scene.json
12
+ ```
13
+
14
+ ```
15
+ feel of /Game/Player
16
+
17
+ top speed 5.62 u/s
18
+ to full speed 383 ms
19
+ to a stop 133 ms
20
+ turnaround 367 ms
21
+ input → motion 1 frame(s)
22
+
23
+ jump apex 0.262 u
24
+ time to apex 133 ms
25
+ airtime 267 ms
26
+ coyote window 100 ms
27
+ jump buffer 150 ms
28
+ ```
29
+
30
+ ## Why this exists
31
+
32
+ **`jumpVelocity: 4` is not a height.** It is an impulse, and what it produces
33
+ depends on gravity, mass, drag and `fallGravity`. The apex in world units and the
34
+ hang time in milliseconds are what you are actually choosing.
35
+
36
+ **The windows are MEASURED, not read.** `coyoteMs` comes from probing — lift the
37
+ character clear of its support, wait, press, see whether it launched, binary
38
+ search the boundary. A `coyoteSeconds: 0.12` that the controller never consults
39
+ reports **0 ms**. That was a real bug in this engine's own 3D controller until
40
+ 0.37, and the JSON looked correct the entire time.
41
+
42
+ ## Reading it
43
+
44
+ | line | what it tells you |
45
+ |---|---|
46
+ | `to full speed` | acceleration. Under ~100 ms is twitchy-responsive; over ~500 ms is weighty. |
47
+ | `to a stop` | how much you slide. A platformer that overshoots ledges has a long one. |
48
+ | `turnaround` | the cost of changing your mind. The number players feel most and name least. |
49
+ | `input → motion` | 1 frame is immediate. More than 2 and something is buffering. |
50
+ | `jump apex` / `airtime` | compare against the gaps and platform heights in your level. |
51
+ | `coyote window` | **0 reads to players as "the controls are broken"**, not as a missing feature. |
52
+ | `jump buffer` | 0 throws away a press made a few frames before landing. |
53
+
54
+ ## It reports, it does not grade
55
+
56
+ There are no PASS/FAIL bands here on purpose. A twitch platformer and a survival
57
+ horror want opposite numbers, and a table of thresholds invented by an engine
58
+ would be confidently wrong for most games. Two exceptions are called out because
59
+ they are almost never intentional: a coyote window of 0 and a jump buffer of 0.
60
+
61
+ ## Tuning loop
62
+
63
+ ```bash
64
+ bunx incanto-feel src/game.scene.json # measure
65
+ # edit coyoteSeconds / jumpBufferSeconds / jumpVelocity / fallGravity
66
+ bunx incanto-feel src/game.scene.json # measure again
67
+ ```
68
+
69
+ The props live on `CharacterController2D` / `CharacterController3D` — see
70
+ `incanto-3d-character.md`.
71
+
72
+ ## Pairs with the playtester
73
+
74
+ `incanto-feel` answers *how does it move*. `incanto-playtest` answers *can it be
75
+ finished*. A level whose jump apex is 0.26 u and whose gaps are 2 u apart will
76
+ show up in the second as `never reached`.
@@ -277,6 +277,12 @@ Signals: `movementStateChanged(state)`
277
277
  | `sprintMultiplier` | `2` | number |
278
278
  | `jumpVelocity` | `4` | number |
279
279
  | `sprintJumpMultiplier` | `1.2` | number |
280
+ | `coyoteSeconds` | `0` | number |
281
+ | `jumpBufferSeconds` | `0` | number |
282
+ | `jumpCutMultiplier` | `1` | number |
283
+ | `maxJumps` | `1` | number |
284
+ | `airControl` | `0.2` | number |
285
+ | `fallGravity` | `2.5` | number |
280
286
  | `floatHeight` | `0.01` | number |
281
287
  | `mouseLook` | `true` | boolean |
282
288
  | `zoomMin` | `0` | number |
@@ -984,6 +990,21 @@ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `presse
984
990
 
985
991
  Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `lineShown` · `choiceMade` · `dialogueFinished`
986
992
 
993
+ ## `UiFrameCapSelect` — `incanto`
994
+
995
+ | Prop | Default | Kind |
996
+ |---|---|---|
997
+ | `anchor` | `"topLeft"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
998
+ | `visible` | `true` | boolean |
999
+ | `focusable` | `true` | boolean |
1000
+ | `draggable` | `false` | boolean |
1001
+ | `dropTarget` | `false` | boolean |
1002
+ | `label` | `"Frame rate"` | string |
1003
+ | `options` | `"30,60,120,0"` | string |
1004
+ | `value` | `""` | string |
1005
+
1006
+ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `changed`
1007
+
987
1008
  ## `UiImage` — `incanto`
988
1009
 
989
1010
  | Prop | Default | Kind |
@@ -1038,6 +1059,36 @@ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `change
1038
1059
 
1039
1060
  Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped`
1040
1061
 
1062
+ ## `UiQualitySelect` — `incanto`
1063
+
1064
+ | Prop | Default | Kind |
1065
+ |---|---|---|
1066
+ | `anchor` | `"topLeft"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
1067
+ | `visible` | `true` | boolean |
1068
+ | `focusable` | `true` | boolean |
1069
+ | `draggable` | `false` | boolean |
1070
+ | `dropTarget` | `false` | boolean |
1071
+ | `label` | `"Quality"` | string |
1072
+ | `options` | `"low,medium,high"` | string |
1073
+ | `value` | `""` | string |
1074
+
1075
+ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `changed`
1076
+
1077
+ ## `UiRenderScaleSelect` — `incanto`
1078
+
1079
+ | Prop | Default | Kind |
1080
+ |---|---|---|
1081
+ | `anchor` | `"topLeft"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
1082
+ | `visible` | `true` | boolean |
1083
+ | `focusable` | `true` | boolean |
1084
+ | `draggable` | `false` | boolean |
1085
+ | `dropTarget` | `false` | boolean |
1086
+ | `label` | `"Resolution"` | string |
1087
+ | `options` | `"0.5,0.75,1"` | string |
1088
+ | `value` | `""` | string |
1089
+
1090
+ Signals: `dragStarted` · `dragCancelled` · `droppedOn` · `dropped` · `changed`
1091
+
1041
1092
  ## `UiSelect` — `incanto`
1042
1093
 
1043
1094
  | Prop | Default | Kind |