incanto 0.28.0 → 0.29.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 (58) hide show
  1. package/README.md +44 -0
  2. package/bin/incanto-editor.mjs +118 -1
  3. package/dist/2d.d.ts +38 -5
  4. package/dist/2d.js +3 -3
  5. package/dist/3d.d.ts +319 -15
  6. package/dist/3d.js +5 -5
  7. package/dist/{behavior-CPibUfnH.d.ts → behavior-BAc0erXF.d.ts} +21 -0
  8. package/dist/{create-game-BRgWpNsa.js → create-game-CNKXGfpr.js} +270 -47
  9. package/dist/{create-game-71TJjW1T.js → create-game-CbuLWorm.js} +53 -14
  10. package/dist/debug.d.ts +51 -6
  11. package/dist/debug.js +242 -19
  12. package/dist/editor-switch-B0wB_DSr.d.ts +59 -0
  13. package/dist/editor-switch-CAKlJMIY.js +161 -0
  14. package/dist/editor.d.ts +49 -0
  15. package/dist/editor.js +8439 -0
  16. package/dist/{gameplay-DEG-TP7D.js → gameplay-L05WgWd1.js} +207 -37
  17. package/dist/gameplay.d.ts +1 -1
  18. package/dist/gameplay.js +1 -1
  19. package/dist/index.d.ts +22 -3
  20. package/dist/index.js +2 -2
  21. package/dist/{loader-DILt9PGC.d.ts → loader-B242FF6N.d.ts} +1 -1
  22. package/dist/net.d.ts +1 -1
  23. package/dist/net.js +2 -2
  24. package/dist/{pathfinding-RWYkNKx9.d.ts → pathfinding-BwD974Ss.d.ts} +1 -1
  25. package/dist/{physics-2d-DiVFFlH3.js → physics-2d-CCVTrKOd.js} +62 -2
  26. package/dist/{physics-3d--y5clE2j.js → physics-3d-BZZLtwJu.js} +439 -8
  27. package/dist/react.d.ts +1 -1
  28. package/dist/react.js +1 -1
  29. package/dist/{register-nObreUQR.js → register-BTg0EM7s.js} +35 -3
  30. package/dist/{register-6R75AC7-.js → register-C44aSduO.js} +5550 -5073
  31. package/dist/{register-CvpSUU3O.js → register-DWcWq4QG.js} +22 -2
  32. package/dist/{register-BFFE1Mh1.js → register-MelqEdza.js} +1 -1
  33. package/dist/test.d.ts +35 -3
  34. package/dist/test.js +104 -10
  35. package/dist/vite.d.ts +53 -1
  36. package/dist/vite.js +94 -2
  37. package/editor/assets/{agent8-CojUfCXN.js → agent8-DEVkEa3d.js} +1 -1
  38. package/editor/assets/debug-zGAtpDF0.js +2 -0
  39. package/editor/assets/index-Bx4UtWYY.js +10586 -0
  40. package/editor/index.html +3 -157
  41. package/package.json +3 -2
  42. package/schemas/scene.schema.json +102 -4
  43. package/skills/incanto-3d-models.md +38 -0
  44. package/skills/incanto-assets.md +13 -0
  45. package/skills/incanto-building-3d-games.md +83 -6
  46. package/skills/incanto-editor.md +151 -0
  47. package/skills/incanto-environment.md +65 -1
  48. package/skills/incanto-node-reference.md +33 -1
  49. package/skills/incanto-physics-and-input.md +45 -6
  50. package/skills/incanto-verifying-your-game.md +51 -2
  51. package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +5 -0
  52. package/templates-app/beacon-isle-3d/package.json +1 -1
  53. package/templates-app/tps-3d/docs/project-3d-rules.md +5 -0
  54. package/templates-app/tps-3d/package.json +1 -1
  55. package/templates-app/village-quest-3d/docs/project-3d-rules.md +5 -0
  56. package/templates-app/village-quest-3d/package.json +1 -1
  57. package/editor/assets/index-D6RQgROR.js +0 -8330
  58. package/editor/assets/index-D8QvwvOm.css +0 -1
package/editor/index.html CHANGED
@@ -5,165 +5,11 @@
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-D6RQgROR.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-Bx4UtWYY.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="./assets/GameServer-C56iOUgF.js">
10
- <link rel="stylesheet" crossorigin href="./assets/index-D8QvwvOm.css">
11
10
  </head>
12
11
  <body>
13
- <header id="topbar">
14
- <div class="brand">
15
- <span class="brand-mark">in</span>
16
- <strong>incanto</strong><span class="brand-sub">editor</span>
17
- </div>
18
- <div id="file-chip" title="">
19
- <svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
20
- <span id="file-path"></span>
21
- </div>
22
- <span id="engine-version" class="pill"></span>
23
- <span class="spacer"></span>
24
- <button type="button" id="lang-btn" class="ghost" title="Language / 언어">
25
- <span id="lang-current">EN</span>
26
- <svg aria-hidden="true" width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="m6 9 6 6 6-6"/></svg>
27
- </button>
28
- <button type="button" id="docs-btn" class="ghost" title="Node documentation">
29
- <svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
30
- docs
31
- </button>
32
- <button type="button" id="scenes-btn" class="ghost" hidden>
33
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2"/></svg>
34
- scenes
35
- </button>
36
- <button type="button" id="fit-btn" class="ghost" title="Zoom to fit (F)">⌖ fit</button>
37
- <button type="button" id="undo-btn" class="ghost" title="Undo (Ctrl/Cmd+Z)" disabled>↩ undo</button>
38
- <button type="button" id="play-btn" class="play" title="Run the scene with physics + input">
39
- <svg aria-hidden="true" width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
40
- play
41
- </button>
42
- <button type="button" id="save-btn" class="primary" disabled>save</button>
43
- </header>
44
- <div id="error-banner" hidden></div>
45
- <div id="play-notice" hidden></div>
46
- <main>
47
- <aside id="tree-pane">
48
- <button type="button" class="pane-title explorer-section section-toggle" data-section="assets">
49
- <span class="chev"><svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="m6 9 6 6 6-6"/></svg></span> assets
50
- <span class="spacer"></span>
51
- <span id="group-add-btn" class="ghost section-add" title="Add a group (folder)" role="button">
52
- <svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M12 11v6M9 14h6"/></svg>
53
- </span>
54
- <span id="asset-add-btn" class="ghost section-add" title="Add an asset" role="button">+</span>
55
- </button>
56
- <div id="asset-tree" data-body="assets"></div>
57
- <button type="button" class="pane-title explorer-section section-toggle" data-section="scene">
58
- <span class="chev"><svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="m6 9 6 6 6-6"/></svg></span> scene
59
- </button>
60
- <div id="scene-body" data-body="scene">
61
- <div id="tree"></div>
62
- <div id="tree-actions">
63
- <select id="add-type" title="Node type to add"></select>
64
- <button type="button" id="add-btn" class="ghost" title="Add child to the selected node">+</button>
65
- <button type="button" id="generate-btn" class="ghost" title="Generate an environment under the selected node">
66
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M18.4 5.6l-2.8 2.8M8.4 15.6l-2.8 2.8"/></svg>
67
- </button>
68
- <button type="button" id="delete-btn" class="ghost danger" title="Delete the selected node">✕</button>
69
- </div>
70
- </div>
71
- </aside>
72
- <section id="viewport-pane">
73
- <div id="mode-toolbar">
74
- <button type="button" id="tool-move" class="tool active" title="Move (W)">
75
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M2 12h20M8 6l4-4 4 4M8 18l4 4 4-4M6 8l-4 4 4 4M18 8l4 4-4 4"/></svg>
76
- </button>
77
- <button type="button" id="tool-rotate" class="tool" title="Rotate (E)">
78
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 3v5h-5"/></svg>
79
- </button>
80
- <button type="button" id="tool-scale" class="tool" title="Scale (R)">
81
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 3 9 15"/><path d="M21 8V3h-5"/><rect x="3" y="13" width="8" height="8" rx="1"/></svg>
82
- </button>
83
- <span class="tool-divider"></span>
84
- <button type="button" id="tool-colliders" class="tool active" title="Show colliders">
85
- <svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="3 2"><rect x="4" y="4" width="16" height="16" rx="2"/></svg>
86
- </button>
87
- </div>
88
- <canvas id="viewport"></canvas>
89
- <canvas id="overlay"></canvas>
90
- <canvas id="play-canvas" hidden></canvas>
91
- <div id="hints-dock">
92
- <div id="hints" class="hints">
93
- <span><b>click</b> select</span><span><b>drag</b> move</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> move/rotate/scale</span><span><b>⇧</b> snap</span><span><b>right-drag</b> pan</span>
94
- </div>
95
- <div id="hints-3d" class="hints" hidden>
96
- <span><b>drag</b> orbit</span><span><b>right-drag</b> pan</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> mode</span><span><b>⇧</b> snap</span><span><b>F</b> frame</span><span><b>0</b> game cam</span>
97
- </div>
98
- <button type="button" id="hints-toggle" title="Controls">
99
- <svg aria-hidden="true" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 10h.01M10 10h.01M14 10h.01M18 10h.01M6 14h.01M18 14h.01M9 14h6"/></svg>
100
- </button>
101
- </div>
102
- <button type="button" id="gameview-btn" class="ghost" title="View through the game camera — exactly what running the scene shows (0)">
103
- <svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7h12v10H3z"/><path d="M15 10l6-3v10l-6-3"/></svg>
104
- game cam
105
- </button>
106
- </section>
107
- <aside id="inspector-pane">
108
- <div class="pane-title">inspector</div>
109
- <div id="inspector"></div>
110
- </aside>
111
- </main>
112
- <div id="picker" hidden>
113
- <div id="picker-card">
114
- <div class="pane-title picker-title">
115
- open a scene
116
- <button type="button" id="picker-close" title="Close (Esc)">✕</button>
117
- </div>
118
- <div id="picker-list"></div>
119
- <div id="picker-new">
120
- <input id="picker-path" type="text" placeholder="src/new-level.scene.json" />
121
- <button type="button" id="picker-create" class="primary">create</button>
122
- </div>
123
- </div>
124
- </div>
125
- <div id="docs" hidden>
126
- <div id="docs-card">
127
- <div class="pane-title picker-title">
128
- incanto nodes
129
- <button type="button" id="docs-close" title="Close (Esc)">✕</button>
130
- </div>
131
- <div id="docs-layout">
132
- <nav id="docs-tabs"></nav>
133
- <div id="docs-body"></div>
134
- </div>
135
- </div>
136
- </div>
137
- <div id="confirm" hidden>
138
- <div id="confirm-card">
139
- <div class="pane-title picker-title">
140
- <span id="confirm-title">still referenced</span>
141
- <button type="button" id="confirm-close" title="Close (Esc)">✕</button>
142
- </div>
143
- <div id="confirm-body">
144
- <div id="confirm-text"></div>
145
- <div id="confirm-list"></div>
146
- </div>
147
- <div id="confirm-actions">
148
- <button type="button" id="confirm-cancel" class="ghost">cancel</button>
149
- <button type="button" id="confirm-delete">unlink &amp; delete</button>
150
- </div>
151
- </div>
152
- </div>
153
- <div id="generate" hidden>
154
- <div id="generate-card">
155
- <div class="pane-title picker-title">
156
- generate environment
157
- <button type="button" id="generate-close" title="Close (Esc)">✕</button>
158
- </div>
159
- <div id="generate-body"></div>
160
- <div id="generate-actions">
161
- <span id="generate-status"></span>
162
- <button type="button" id="generate-cancel" class="ghost">cancel</button>
163
- <button type="button" id="generate-insert" class="primary">insert</button>
164
- </div>
165
- </div>
166
- </div>
167
- <div id="popover" hidden></div>
12
+ <!-- The shell is built by src/shell.ts (generated from this file by
13
+ scripts/bundle-assets.mjs) so a running GAME can mount the same editor. -->
168
14
  </body>
169
15
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incanto",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "Vibe-coding-first web game engine SDK — JSON-driven scenes on three.js",
5
5
  "keywords": [
6
6
  "game-engine",
@@ -48,7 +48,8 @@
48
48
  "./vite": "./dist/vite.js",
49
49
  "./package.json": "./package.json",
50
50
  "./schemas/*": "./schemas/*",
51
- "./assets/*": "./assets/*"
51
+ "./assets/*": "./assets/*",
52
+ "./editor": "./dist/editor.js"
52
53
  },
53
54
  "scripts": {
54
55
  "build": "tsdown",
@@ -588,6 +588,9 @@
588
588
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
589
589
  "default": "default"
590
590
  },
591
+ "snapToGround": {
592
+ "default": null
593
+ },
591
594
  "texture": {
592
595
  "type": "string",
593
596
  "default": ""
@@ -855,6 +858,9 @@
855
858
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
856
859
  "default": "default"
857
860
  },
861
+ "snapToGround": {
862
+ "default": null
863
+ },
858
864
  "collider": {
859
865
  "type": "object",
860
866
  "default": {}
@@ -1073,6 +1079,9 @@
1073
1079
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1074
1080
  "default": "default"
1075
1081
  },
1082
+ "snapToGround": {
1083
+ "default": null
1084
+ },
1076
1085
  "mode": {
1077
1086
  "type": "string",
1078
1087
  "enum": ["screen", "y", "none"],
@@ -1173,6 +1182,9 @@
1173
1182
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1174
1183
  "default": "default"
1175
1184
  },
1185
+ "snapToGround": {
1186
+ "default": null
1187
+ },
1176
1188
  "target": {
1177
1189
  "type": "string",
1178
1190
  "default": ""
@@ -1276,6 +1288,9 @@
1276
1288
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1277
1289
  "default": "default"
1278
1290
  },
1291
+ "snapToGround": {
1292
+ "default": null
1293
+ },
1279
1294
  "target": {
1280
1295
  "type": "string",
1281
1296
  "default": ""
@@ -1506,6 +1521,9 @@
1506
1521
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1507
1522
  "default": "default"
1508
1523
  },
1524
+ "snapToGround": {
1525
+ "default": null
1526
+ },
1509
1527
  "fov": {
1510
1528
  "type": "number",
1511
1529
  "default": 60
@@ -1730,6 +1748,10 @@
1730
1748
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1731
1749
  "default": "default"
1732
1750
  },
1751
+ "snapToGround": {
1752
+ "type": "boolean",
1753
+ "default": true
1754
+ },
1733
1755
  "collider": {
1734
1756
  "type": "object",
1735
1757
  "default": {}
@@ -1743,10 +1765,6 @@
1743
1765
  "maxItems": 3,
1744
1766
  "default": [0, 0, 0]
1745
1767
  },
1746
- "snapToGround": {
1747
- "type": "boolean",
1748
- "default": true
1749
- },
1750
1768
  "slopeLimitDeg": {
1751
1769
  "type": "number",
1752
1770
  "default": 45
@@ -1919,6 +1937,9 @@
1919
1937
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
1920
1938
  "default": "default"
1921
1939
  },
1940
+ "snapToGround": {
1941
+ "default": null
1942
+ },
1922
1943
  "view": {
1923
1944
  "type": "string",
1924
1945
  "enum": ["free", "firstPerson", "quarter", "side"],
@@ -2219,6 +2240,9 @@
2219
2240
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
2220
2241
  "default": "default"
2221
2242
  },
2243
+ "snapToGround": {
2244
+ "default": null
2245
+ },
2222
2246
  "color": {
2223
2247
  "type": "string",
2224
2248
  "default": "#ffffff"
@@ -2338,6 +2362,9 @@
2338
2362
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
2339
2363
  "default": "default"
2340
2364
  },
2365
+ "snapToGround": {
2366
+ "default": null
2367
+ },
2341
2368
  "density": {
2342
2369
  "type": "string",
2343
2370
  "enum": ["lush", "sparse", "none"],
@@ -2482,6 +2509,9 @@
2482
2509
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
2483
2510
  "default": "default"
2484
2511
  },
2512
+ "snapToGround": {
2513
+ "default": null
2514
+ },
2485
2515
  "kind": {
2486
2516
  "type": "string",
2487
2517
  "enum": ["grass", "flowers", "reeds"],
@@ -2732,6 +2762,9 @@
2732
2762
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
2733
2763
  "default": "default"
2734
2764
  },
2765
+ "snapToGround": {
2766
+ "default": null
2767
+ },
2735
2768
  "mesh": {
2736
2769
  "type": "string",
2737
2770
  "enum": ["box", "sphere", "capsule", "plane", "cylinder", "gem"],
@@ -2761,6 +2794,9 @@
2761
2794
  "receiveShadow": {
2762
2795
  "type": "boolean",
2763
2796
  "default": false
2797
+ },
2798
+ "collider": {
2799
+ "default": null
2764
2800
  }
2765
2801
  },
2766
2802
  "additionalProperties": false
@@ -2986,6 +3022,9 @@
2986
3022
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
2987
3023
  "default": "default"
2988
3024
  },
3025
+ "snapToGround": {
3026
+ "default": null
3027
+ },
2989
3028
  "type": {
2990
3029
  "type": "string",
2991
3030
  "enum": ["fixed", "spherical", "rope", "spring"],
@@ -3230,6 +3269,9 @@
3230
3269
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3231
3270
  "default": "default"
3232
3271
  },
3272
+ "snapToGround": {
3273
+ "default": null
3274
+ },
3233
3275
  "sections": {
3234
3276
  "type": "array",
3235
3277
  "default": []
@@ -3349,6 +3391,9 @@
3349
3391
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3350
3392
  "default": "default"
3351
3393
  },
3394
+ "snapToGround": {
3395
+ "default": null
3396
+ },
3352
3397
  "mesh": {
3353
3398
  "type": "string",
3354
3399
  "enum": ["box", "sphere", "capsule", "plane", "cylinder", "gem"],
@@ -3471,6 +3516,9 @@
3471
3516
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3472
3517
  "default": "default"
3473
3518
  },
3519
+ "snapToGround": {
3520
+ "default": null
3521
+ },
3474
3522
  "model": {
3475
3523
  "type": "string",
3476
3524
  "default": ""
@@ -3491,6 +3539,14 @@
3491
3539
  "type": "boolean",
3492
3540
  "default": true
3493
3541
  },
3542
+ "animationSpeed": {
3543
+ "type": "number",
3544
+ "default": 1
3545
+ },
3546
+ "animationOffset": {
3547
+ "type": "number",
3548
+ "default": 0
3549
+ },
3494
3550
  "animationUpper": {
3495
3551
  "type": "string",
3496
3552
  "default": ""
@@ -3817,6 +3873,9 @@
3817
3873
  "type": "string",
3818
3874
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3819
3875
  "default": "default"
3876
+ },
3877
+ "snapToGround": {
3878
+ "default": null
3820
3879
  }
3821
3880
  },
3822
3881
  "additionalProperties": false
@@ -3913,6 +3972,9 @@
3913
3972
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
3914
3973
  "default": "default"
3915
3974
  },
3975
+ "snapToGround": {
3976
+ "default": null
3977
+ },
3916
3978
  "color": {
3917
3979
  "type": "string",
3918
3980
  "default": "#ffffff"
@@ -4221,6 +4283,9 @@
4221
4283
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
4222
4284
  "default": "effects"
4223
4285
  },
4286
+ "snapToGround": {
4287
+ "default": null
4288
+ },
4224
4289
  "preset": {
4225
4290
  "type": "string",
4226
4291
  "enum": [
@@ -4554,6 +4619,9 @@
4554
4619
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
4555
4620
  "default": "default"
4556
4621
  },
4622
+ "snapToGround": {
4623
+ "default": null
4624
+ },
4557
4625
  "collider": {
4558
4626
  "type": "object",
4559
4627
  "default": {}
@@ -4682,6 +4750,9 @@
4682
4750
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
4683
4751
  "default": "default"
4684
4752
  },
4753
+ "snapToGround": {
4754
+ "default": null
4755
+ },
4685
4756
  "path": {
4686
4757
  "type": "array",
4687
4758
  "default": []
@@ -4969,6 +5040,9 @@
4969
5040
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
4970
5041
  "default": "default"
4971
5042
  },
5043
+ "snapToGround": {
5044
+ "default": null
5045
+ },
4972
5046
  "texture": {
4973
5047
  "type": "string",
4974
5048
  "default": ""
@@ -5216,6 +5290,9 @@
5216
5290
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
5217
5291
  "default": "default"
5218
5292
  },
5293
+ "snapToGround": {
5294
+ "default": null
5295
+ },
5219
5296
  "collider": {
5220
5297
  "type": "object",
5221
5298
  "default": {}
@@ -5315,6 +5392,9 @@
5315
5392
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
5316
5393
  "default": "terrain"
5317
5394
  },
5395
+ "snapToGround": {
5396
+ "default": null
5397
+ },
5318
5398
  "size": {
5319
5399
  "type": "array",
5320
5400
  "items": {
@@ -5664,6 +5744,9 @@
5664
5744
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
5665
5745
  "default": "default"
5666
5746
  },
5747
+ "snapToGround": {
5748
+ "default": null
5749
+ },
5667
5750
  "width": {
5668
5751
  "type": "number",
5669
5752
  "default": 0.3
@@ -5787,6 +5870,9 @@
5787
5870
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
5788
5871
  "default": "default"
5789
5872
  },
5873
+ "snapToGround": {
5874
+ "default": null
5875
+ },
5790
5876
  "tier": {
5791
5877
  "type": "string",
5792
5878
  "enum": ["simple", "medium", "high"],
@@ -6452,6 +6538,9 @@
6452
6538
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
6453
6539
  "default": "default"
6454
6540
  },
6541
+ "snapToGround": {
6542
+ "default": null
6543
+ },
6455
6544
  "voxels": {
6456
6545
  "type": "array",
6457
6546
  "default": []
@@ -6552,6 +6641,9 @@
6552
6641
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
6553
6642
  "default": "default"
6554
6643
  },
6644
+ "snapToGround": {
6645
+ "default": null
6646
+ },
6555
6647
  "size": {
6556
6648
  "type": "array",
6557
6649
  "items": {
@@ -6610,6 +6702,9 @@
6610
6702
  "type": "boolean",
6611
6703
  "default": true
6612
6704
  },
6705
+ "reflectivity": {
6706
+ "default": null
6707
+ },
6613
6708
  "interaction": {
6614
6709
  "type": "boolean",
6615
6710
  "default": true
@@ -6775,6 +6870,9 @@
6775
6870
  "enum": ["background", "terrain", "default", "characters", "effects", "overlay"],
6776
6871
  "default": "default"
6777
6872
  },
6873
+ "snapToGround": {
6874
+ "default": null
6875
+ },
6778
6876
  "size": {
6779
6877
  "type": "array",
6780
6878
  "items": {
@@ -150,6 +150,44 @@ model file, or an animation-asset reference:
150
150
  Models need LIGHT (standard materials): add a DirectionalLight3D or scene
151
151
  `environment.ambient` or you will see black silhouettes.
152
152
 
153
+ ## A model that just animates — no script
154
+
155
+ Setting `animation` is the whole thing. The clip starts the moment the model
156
+ mounts and keeps looping; nothing has to call play(). That is how you dress a
157
+ scene with a torch that flickers, a flag that waves, a fish that swims, or an
158
+ idling NPC:
159
+
160
+ ```json
161
+ { "name": "Torch", "type": "ModelInstance3D",
162
+ "props": { "model": "$torch", "animation": "Flicker" } }
163
+ ```
164
+
165
+ Four props shape it, and they are all live (a behavior or the editor can change
166
+ them mid-play without restarting the clip):
167
+
168
+ | prop | default | what it does |
169
+ |---|---|---|
170
+ | `animation` | `""` | embedded clip name, or `$key` of an animation asset. `""` = still |
171
+ | `animationLoop` | `true` | `false` = play once, hold the last pose, emit `animationFinished` |
172
+ | `animationSpeed` | `1` | playback rate. `0.5` half, `2` double, `0` freezes the pose, **negative plays backwards** (a closing door is an opening one reversed) |
173
+ | `animationOffset` | `0` | seconds into the clip to start at, wrapped into its duration |
174
+
175
+ **`animationOffset` is what stops a scene looking like copies.** Ten torches all
176
+ starting at 0 flicker in perfect unison and the eye reads it instantly. Give each
177
+ a different offset and the same clip becomes a crowd:
178
+
179
+ ```json
180
+ { "name": "Torch2", "type": "ModelInstance3D",
181
+ "props": { "model": "$torch", "animation": "Flicker",
182
+ "animationOffset": 0.7, "animationSpeed": 0.9 } }
183
+ ```
184
+
185
+ A generator or scatter can hand out `index * 0.37` without knowing the clip
186
+ length — offsets wrap, so any number is legal.
187
+
188
+ For a second clip on the upper body only (attack while running), see
189
+ `animationUpper` / `animationUpperLoop` / `upperBodyRoot` in the node reference.
190
+
153
191
  ## How loading works
154
192
 
155
193
  `Renderer3D` owns an `AssetStore3D` (GLTFLoader + `@pixiv/three-vrm`'s VRMLoaderPlugin).
@@ -105,6 +105,19 @@ const { asset, props } = spriteFromLibraryMeta(animJson, {
105
105
  For 3D files, ALWAYS inspect before placing: `bunx incanto-model file.glb`
106
106
  (bounds, animations, rig — see incanto-3d-models).
107
107
 
108
+ ### The agent8 library, from inside the editor
109
+
110
+ `bunx incanto-editor --token <v8 access token>` puts a **📚** button on every
111
+ field that takes a resource. It browses the same catalog the agent8 workbench
112
+ does (2D sprites; 3D characters/monsters/objects/vehicles/weapons/polyhaven/
113
+ textures), previews a GLB with the engine and an image as an image, and on pick
114
+ writes the URL — or, for a `$assetKey` field, writes the scene `assets{}` entry
115
+ AND the ref together. See `incanto-editor` for the token and proxy details.
116
+
117
+ Everything the library hands you is an ordinary URL on the agent8 CDN, so a
118
+ scene built that way stays plain JSON you can also hand-write.
119
+
120
+
108
121
  ## 3. No art yet? Ship gameplay anyway
109
122
 
110
123
  - `ColorRect2D` — solid rectangles for paddles/walls/platforms/flashes.