incanto 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/incanto-check.mjs +6 -4
- package/dist/2d.d.ts +93 -3
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +45 -4
- package/dist/3d.js +4 -4
- package/dist/{audio-player-VSjk_vG8.d.ts → audio-player-Dyjg5k92.d.ts} +1 -1
- package/dist/audit-C6rMyict.js +58 -0
- package/dist/{behavior-e3kAmPGC.d.ts → behavior-Bod1AyJS.d.ts} +211 -174
- package/dist/{create-game-CEFoFN8d.js → create-game-66c4iYJE.js} +76 -6
- package/dist/{create-game-X5iRu6pf.js → create-game-BNDSbhy-.js} +88 -6
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +3 -0
- package/dist/{errors-BMFaY68Q.d.ts → errors-1dXlIwoR.d.ts} +7 -1
- package/dist/{gameplay-CDFgSG6z.js → gameplay-DPMgZk9W.js} +108 -1
- package/dist/gameplay.d.ts +44 -3
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +151 -9
- package/dist/index.js +189 -4
- package/dist/{loader-y_X4zYO0.d.ts → loader-BcUDfNHn.d.ts} +1 -1
- package/dist/net.d.ts +46 -2
- package/dist/net.js +54 -2
- package/dist/particle-sim-CyUU7HVU.js +281 -0
- package/dist/{physics-2d-DmQ540uR.js → physics-2d-q2N362ph.js} +45 -4
- package/dist/{physics-3d-CDjuhtt_.js → physics-3d-CvHr31d4.js} +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-CscQqB7V.js → register-Cbs7QxoV.js} +139 -4
- package/dist/{register-ClKnoILk.js → register-Cqjxrfq0.js} +254 -4
- package/dist/{register-C35HDZpm.js → register-CxmuI9FL.js} +1 -1
- package/dist/{particle-sim-CrTE7c02.js → register-DRPIjrKG.js} +1185 -278
- package/dist/test.d.ts +4 -10
- package/dist/test.js +11 -16
- package/editor/assets/{agent8-1WJU-yXr.js → agent8-B8QnWCeP.js} +1 -1
- package/editor/assets/{index-DzYFgZbl.js → index-CVhnNkb3.js} +81 -81
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +427 -0
- package/skills/incanto-3d-character.md +14 -0
- package/skills/incanto-audio.md +23 -0
- package/skills/incanto-building-2d-games.md +31 -0
- package/skills/incanto-building-3d-games.md +21 -0
- package/skills/incanto-gameplay-behaviors.md +28 -0
- package/skills/incanto-hud.md +24 -0
- package/skills/incanto-multiplayer.md +27 -0
- package/skills/incanto-node-reference.md +73 -0
- package/skills/incanto-physics-and-input.md +9 -0
- package/skills/incanto-verifying-your-game.md +40 -0
- package/dist/register-Dl_ixIJe.js +0 -834
|
@@ -140,6 +140,33 @@ const manager = await NetworkManager.create(engine, { transport: local.createCli
|
|
|
140
140
|
engine.updated.connect((dt) => void local.tick(Math.min(dt, 0.05) * 1000));
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
### Split-screen preview in one call (`createSplitScreen`)
|
|
144
|
+
|
|
145
|
+
Testing multiplayer alone means playing BOTH sides. `createSplitScreen` wires
|
|
146
|
+
the whole N-panel harness — one LocalGameServer, one engine + NetworkManager
|
|
147
|
+
per player — so you only supply the per-panel renderer/input:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { createSplitScreen, registerNodesNet } from 'incanto/net';
|
|
151
|
+
|
|
152
|
+
const canvases = [document.getElementById('p1'), document.getElementById('p2')];
|
|
153
|
+
const { players, server, dispose } = await createSplitScreen({
|
|
154
|
+
scene: gameJson, // shared scene (each panel gets its own copy)
|
|
155
|
+
server: Server, // your v2 Server class (optional)
|
|
156
|
+
scenes: { 'remote-player': remoteJson }, // NetworkSpawner scenes, every panel
|
|
157
|
+
accounts: ['p1', 'p2'], // one panel per account (default)
|
|
158
|
+
setup: ({ engine }, i) => { // finish wiring each panel
|
|
159
|
+
new Renderer2D({ canvas: canvases[i], engine });
|
|
160
|
+
engine.input.attachKeyboard(i === 0 ? window : canvases[i]); // split inputs!
|
|
161
|
+
engine.start();
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The first panel's clock pumps `server.tick` (so `$roomTick` runs) — don't add
|
|
167
|
+
your own. `dispose()` tears every panel down. Going live is unchanged: ONE
|
|
168
|
+
client per browser with `createAgent8Server()` as the transport.
|
|
169
|
+
|
|
143
170
|
It runs the SAME class body the cloud runs: the v2 globals (`$sender`/`$global`/
|
|
144
171
|
`$room`/`$lock`) are injected per call, a FRESH `Server` instance runs per request
|
|
145
172
|
(so `this.*` never persists), and calls are serialized (no global leaks across
|
|
@@ -241,6 +241,7 @@ Signals: `triggerEnter(other)` · `triggerExit(other)`
|
|
|
241
241
|
| `sprintAction` | `"sprint"` | string |
|
|
242
242
|
| `skinPath` | `"../Skin"` | string |
|
|
243
243
|
| `skinYawOffset` | `0` | number |
|
|
244
|
+
| `animations` | `{}` | object |
|
|
244
245
|
|
|
245
246
|
Signals: `movementStateChanged(state)`
|
|
246
247
|
|
|
@@ -711,6 +712,25 @@ Signals: `triggerEnter(other)` · `triggerExit(other)`
|
|
|
711
712
|
| `textureBase` | `"https://agent8-games.verse8.io/assets/3D/default/textures/terrain"` | string |
|
|
712
713
|
| `basins` | `[]` | array |
|
|
713
714
|
|
|
715
|
+
## `TileMap2D` — `incanto/2d`
|
|
716
|
+
|
|
717
|
+
| Prop | Default | Kind |
|
|
718
|
+
|---|---|---|
|
|
719
|
+
| `position` | `[0,0]` | array |
|
|
720
|
+
| `rotation` | `0` | number |
|
|
721
|
+
| `static` | `false` | boolean |
|
|
722
|
+
| `scale` | `[1,1]` | array |
|
|
723
|
+
| `renderOrder` | `0` | number |
|
|
724
|
+
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
725
|
+
| `visible` | `true` | boolean |
|
|
726
|
+
| `texture` | `""` | string |
|
|
727
|
+
| `tileSize` | `32` | number |
|
|
728
|
+
| `columns` | `0` | number |
|
|
729
|
+
| `cells` | `[]` | array |
|
|
730
|
+
| `legend` | `{}` | object |
|
|
731
|
+
| `solid` | `[]` | array |
|
|
732
|
+
| `opacity` | `1` | number |
|
|
733
|
+
|
|
714
734
|
## `Timer` — `incanto`
|
|
715
735
|
|
|
716
736
|
| Prop | Default | Kind |
|
|
@@ -721,6 +741,25 @@ Signals: `triggerEnter(other)` · `triggerExit(other)`
|
|
|
721
741
|
|
|
722
742
|
Signals: `timeout`
|
|
723
743
|
|
|
744
|
+
## `Trail3D` — `incanto/3d`
|
|
745
|
+
|
|
746
|
+
| Prop | Default | Kind |
|
|
747
|
+
|---|---|---|
|
|
748
|
+
| `position` | `[0,0,0]` | array |
|
|
749
|
+
| `rotation` | `[0,0,0]` | array |
|
|
750
|
+
| `static` | `false` | boolean |
|
|
751
|
+
| `scale` | `[1,1,1]` | array |
|
|
752
|
+
| `visible` | `true` | boolean |
|
|
753
|
+
| `renderOrder` | `0` | number |
|
|
754
|
+
| `orderGroup` | `"default"` | one of: `background` `terrain` `default` `characters` `effects` `overlay` |
|
|
755
|
+
| `width` | `0.3` | number |
|
|
756
|
+
| `color` | `"#ffffff"` | string |
|
|
757
|
+
| `opacity` | `0.8` | number |
|
|
758
|
+
| `seconds` | `0.6` | number |
|
|
759
|
+
| `emitting` | `true` | boolean |
|
|
760
|
+
| `additive` | `false` | boolean |
|
|
761
|
+
| `minDistance` | `0.05` | number |
|
|
762
|
+
|
|
724
763
|
## `Tree3D` — `incanto/3d`
|
|
725
764
|
|
|
726
765
|
| Prop | Default | Kind |
|
|
@@ -780,6 +819,31 @@ Signals: `bannerShown`
|
|
|
780
819
|
| `background` | `"rgba(0,0,0,0.5)"` | string |
|
|
781
820
|
| `label` | `""` | string |
|
|
782
821
|
|
|
822
|
+
## `UiButton` — `incanto`
|
|
823
|
+
|
|
824
|
+
| Prop | Default | Kind |
|
|
825
|
+
|---|---|---|
|
|
826
|
+
| `anchor` | `"topLeft"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
|
|
827
|
+
| `visible` | `true` | boolean |
|
|
828
|
+
| `text` | `"OK"` | string |
|
|
829
|
+
| `size` | `16` | number |
|
|
830
|
+
| `color` | `"#ffffff"` | string |
|
|
831
|
+
| `background` | `"rgba(255,255,255,0.14)"` | string |
|
|
832
|
+
| `disabled` | `false` | boolean |
|
|
833
|
+
|
|
834
|
+
Signals: `pressed`
|
|
835
|
+
|
|
836
|
+
## `UiDialogue` — `incanto`
|
|
837
|
+
|
|
838
|
+
| Prop | Default | Kind |
|
|
839
|
+
|---|---|---|
|
|
840
|
+
| `anchor` | `"bottom"` | one of: `topLeft` `top` `topRight` `left` `center` `right` `bottomLeft` `bottom` `bottomRight` |
|
|
841
|
+
| `visible` | `true` | boolean |
|
|
842
|
+
| `charsPerSecond` | `40` | number |
|
|
843
|
+
| `width` | `520` | number |
|
|
844
|
+
|
|
845
|
+
Signals: `lineShown` · `choiceMade` · `dialogueFinished`
|
|
846
|
+
|
|
783
847
|
## `UiText` — `incanto`
|
|
784
848
|
|
|
785
849
|
| Prop | Default | Kind |
|
|
@@ -951,6 +1015,15 @@ Signals: `arrived`
|
|
|
951
1015
|
| `frequency` | `1` | number |
|
|
952
1016
|
| `mode` | `"position"` | one of: `position` `rotation` `scale` |
|
|
953
1017
|
|
|
1018
|
+
### `PathFollow`
|
|
1019
|
+
|
|
1020
|
+
| Prop | Default | Kind |
|
|
1021
|
+
|---|---|---|
|
|
1022
|
+
| `speed` | `120` | number |
|
|
1023
|
+
| `loop` | `false` | boolean |
|
|
1024
|
+
|
|
1025
|
+
Signals: `waypointReached` · `arrived`
|
|
1026
|
+
|
|
954
1027
|
### `Patrol`
|
|
955
1028
|
|
|
956
1029
|
| Prop | Default | Kind |
|
|
@@ -133,6 +133,15 @@ Injected state combines with key state (vectors clamped to unit length).
|
|
|
133
133
|
- Reference: [examples/2d-phaser-sprite-character-gravity](https://github.com/rareboe/Incanto/tree/main/examples/2d-phaser-sprite-character-gravity) — gravity, jump, attack lockout, custom
|
|
134
134
|
`Player` node type. Verified in Chromium end-to-end.
|
|
135
135
|
|
|
136
|
+
## Platformer staples (2D)
|
|
137
|
+
|
|
138
|
+
- **One-way platforms**: `"collider": { "shape": "rect", "size": [300, 20],
|
|
139
|
+
"oneWay": true }` on a StaticBody2D — characters jump up THROUGH it and
|
|
140
|
+
land ON it (solid only when falling from above). The Mario ledge.
|
|
141
|
+
- **Moving platforms carry riders automatically**: a CharacterBody2D
|
|
142
|
+
standing on ANY body follows that body's movement (elevators, patrol
|
|
143
|
+
platforms — just animate the platform's `position`; the character rides).
|
|
144
|
+
|
|
136
145
|
## Joints (Joint2D / Joint3D)
|
|
137
146
|
|
|
138
147
|
Link two bodies: put the joint node as a CHILD of body A, point `target` at
|
|
@@ -189,3 +189,43 @@ thing gating it: keep it `false` (or dev-gated) in anything you publish.
|
|
|
189
189
|
seeded run reproduces exactly.
|
|
190
190
|
- A run that "does nothing": remember the first engine tick only primes the
|
|
191
191
|
clock — `runScript` already handles this for you.
|
|
192
|
+
|
|
193
|
+
## Finding a node ON SCREEN (selection highlight)
|
|
194
|
+
|
|
195
|
+
Selecting a node in the dev overlay's Explorer draws its world-space
|
|
196
|
+
bounding box as an ORANGE outline in the running game (children included;
|
|
197
|
+
depth-test off, so it shows through walls). Extent-less nodes get a small
|
|
198
|
+
marker cube at their position. That is the fastest answer to "which thing
|
|
199
|
+
on screen IS this node?" — and the reverse of it: walk the tree clicking
|
|
200
|
+
rows until the orange box lands on the thing you're hunting.
|
|
201
|
+
|
|
202
|
+
## Semantic warnings (audit)
|
|
203
|
+
|
|
204
|
+
`incanto-check` now WARNS about scenes that load fine but play wrong: no
|
|
205
|
+
`current` camera, physics bodies without colliders, animated nodes frozen
|
|
206
|
+
inside a `static` subtree, HUD widgets outside a HudLayer. Programmatic:
|
|
207
|
+
`auditScene(json)` from `incanto` or `incanto/test` returns the warnings.
|
|
208
|
+
|
|
209
|
+
## Deterministic replay (record once, regression-test forever)
|
|
210
|
+
|
|
211
|
+
The engine is fully deterministic under a seed + injected clock, so a
|
|
212
|
+
recording of (tick timestamps + input events) replays BIT-identically:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { Engine, loadScene, replay, startRecording } from 'incanto';
|
|
216
|
+
|
|
217
|
+
// while playing (dev build):
|
|
218
|
+
const rec = startRecording(engine);
|
|
219
|
+
// ... play the level ...
|
|
220
|
+
save.set('replays/level1', rec.stop());
|
|
221
|
+
|
|
222
|
+
// in a headless test:
|
|
223
|
+
const engine = new Engine({ seed: SAME_SEED });
|
|
224
|
+
engine.setScene(loadScene(sceneJson));
|
|
225
|
+
replay(engine, recording, { onTick(i) { /* mid-run asserts */ } });
|
|
226
|
+
expect(player.position).toEqual(expected); // exact, not approximate
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Rules that make it hold (the engine's own rules anyway): use `engine.rng`
|
|
230
|
+
never Math.random, dt/`engine.time` never Date.now. Gamepads replay through
|
|
231
|
+
the ACTIONS they were bound to, not raw pad state.
|