@worldmesh/runtime 0.1.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/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/abilities/abilities.d.ts +9 -0
- package/dist/abilities/abilities.d.ts.map +1 -0
- package/dist/abilities/abilities.js +25 -0
- package/dist/abilities/abilities.js.map +1 -0
- package/dist/camera/cameraRig.d.ts +39 -0
- package/dist/camera/cameraRig.d.ts.map +1 -0
- package/dist/camera/cameraRig.js +88 -0
- package/dist/camera/cameraRig.js.map +1 -0
- package/dist/controls/input.d.ts +64 -0
- package/dist/controls/input.d.ts.map +1 -0
- package/dist/controls/input.js +236 -0
- package/dist/controls/input.js.map +1 -0
- package/dist/controls/keymap.d.ts +8 -0
- package/dist/controls/keymap.d.ts.map +1 -0
- package/dist/controls/keymap.js +21 -0
- package/dist/controls/keymap.js.map +1 -0
- package/dist/controls/touch.d.ts +43 -0
- package/dist/controls/touch.d.ts.map +1 -0
- package/dist/controls/touch.js +329 -0
- package/dist/controls/touch.js.map +1 -0
- package/dist/core/events.d.ts +9 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +27 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/worldmesh.d.ts +10 -0
- package/dist/core/worldmesh.d.ts.map +1 -0
- package/dist/core/worldmesh.js +283 -0
- package/dist/core/worldmesh.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/movement/collision.d.ts +39 -0
- package/dist/movement/collision.d.ts.map +1 -0
- package/dist/movement/collision.js +93 -0
- package/dist/movement/collision.js.map +1 -0
- package/dist/movement/controller.d.ts +53 -0
- package/dist/movement/controller.d.ts.map +1 -0
- package/dist/movement/controller.js +200 -0
- package/dist/movement/controller.js.map +1 -0
- package/dist/net/adapter.d.ts +22 -0
- package/dist/net/adapter.d.ts.map +1 -0
- package/dist/net/adapter.js +8 -0
- package/dist/net/adapter.js.map +1 -0
- package/dist/player/avatar.d.ts +29 -0
- package/dist/player/avatar.d.ts.map +1 -0
- package/dist/player/avatar.js +420 -0
- package/dist/player/avatar.js.map +1 -0
- package/dist/player/player.d.ts +30 -0
- package/dist/player/player.d.ts.map +1 -0
- package/dist/player/player.js +76 -0
- package/dist/player/player.js.map +1 -0
- package/dist/portals/portals.d.ts +34 -0
- package/dist/portals/portals.d.ts.map +1 -0
- package/dist/portals/portals.js +132 -0
- package/dist/portals/portals.js.map +1 -0
- package/dist/types.d.ts +228 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/overlay.d.ts +19 -0
- package/dist/ui/overlay.d.ts.map +1 -0
- package/dist/ui/overlay.js +370 -0
- package/dist/ui/overlay.js.map +1 -0
- package/package.json +63 -0
- package/src/abilities/abilities.ts +30 -0
- package/src/camera/cameraRig.ts +106 -0
- package/src/controls/input.ts +252 -0
- package/src/controls/keymap.ts +23 -0
- package/src/controls/touch.ts +378 -0
- package/src/core/events.ts +31 -0
- package/src/core/worldmesh.ts +313 -0
- package/src/index.ts +46 -0
- package/src/movement/collision.ts +109 -0
- package/src/movement/controller.ts +248 -0
- package/src/net/adapter.ts +28 -0
- package/src/player/avatar.ts +495 -0
- package/src/player/player.ts +91 -0
- package/src/portals/portals.ts +173 -0
- package/src/types.ts +230 -0
- package/src/ui/overlay.ts +398 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Elias Willnat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @worldmesh/runtime
|
|
2
|
+
|
|
3
|
+
The shared [WorldMesh](https://github.com/eliaswillnat/worldmesh) navigation
|
|
4
|
+
runtime: controls, movement, camera, player, abilities and portals.
|
|
5
|
+
|
|
6
|
+
WorldMesh is a lightweight open network for independently hosted 3D worlds. It
|
|
7
|
+
supplies the one thing separately hosted worlds need in common — a navigation
|
|
8
|
+
standard — so that moving through an unfamiliar world feels like moving through
|
|
9
|
+
a familiar one. This package is that standard, as code.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @worldmesh/runtime three
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`three` is a peer dependency (`>=0.160.0`): the runtime drives your renderer,
|
|
18
|
+
your scene and your camera, so it must use the same copy of Three.js you do.
|
|
19
|
+
|
|
20
|
+
The package is ESM only and targets ES2022 browsers. It touches `window` and
|
|
21
|
+
`document` when you create a world, so call it from the browser, not during SSR.
|
|
22
|
+
|
|
23
|
+
## Use it
|
|
24
|
+
|
|
25
|
+
If you already have a scene, a camera and a renderer, this is the whole job:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { createWorldMesh } from '@worldmesh/runtime';
|
|
29
|
+
|
|
30
|
+
const world = createWorldMesh({
|
|
31
|
+
scene,
|
|
32
|
+
camera,
|
|
33
|
+
renderer,
|
|
34
|
+
spawn: [0, 2, 0],
|
|
35
|
+
colliders, // things to stand on and bump into
|
|
36
|
+
abilities: { doubleJump: true },
|
|
37
|
+
portals: [{ url: 'https://someone-elses-world.example', position: [6, 0, -6] }],
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You get WASD + arrow keys, mouse look, jump, sprint, interact, first/third
|
|
42
|
+
person with a consistent toggle, pointer-lock handling, touch controls on touch
|
|
43
|
+
devices, the shared overlay and portals between worlds.
|
|
44
|
+
|
|
45
|
+
Removing the `createWorldMesh` call leaves you with the Three.js project you
|
|
46
|
+
started with.
|
|
47
|
+
|
|
48
|
+
## What is exported
|
|
49
|
+
|
|
50
|
+
| | |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `createWorldMesh` | the one call a world needs |
|
|
53
|
+
| `Input`, `TouchControls`, `DEFAULT_KEYMAP`, `resolveKeymap` | the control convention |
|
|
54
|
+
| `MovementController`, `CollisionWorld`, `DEFAULT_TUNING` | movement and collision |
|
|
55
|
+
| `CameraRig`, `Player`, `createDefaultAvatar`, `AVATAR_EXPRESSIONS` | camera and figure |
|
|
56
|
+
| `PortalManager`, `buildTravelUrl`, `getReferringWorld` | travel between worlds |
|
|
57
|
+
| `Overlay`, `Emitter` | the shared overlay, a tiny typed emitter |
|
|
58
|
+
| `serializePlayerState`, `deserializePlayerState`, `NetworkAdapter` | the multiplayer seam |
|
|
59
|
+
| `WORLDMESH_VERSION`, `WORLDMESH_PROTOCOL` | what your world is speaking |
|
|
60
|
+
|
|
61
|
+
Full option, handle and event reference:
|
|
62
|
+
[docs/compatibility.md](https://github.com/eliaswillnat/worldmesh/blob/main/docs/compatibility.md).
|
|
63
|
+
Control convention:
|
|
64
|
+
[docs/controls.md](https://github.com/eliaswillnat/worldmesh/blob/main/docs/controls.md).
|
|
65
|
+
|
|
66
|
+
## Versions
|
|
67
|
+
|
|
68
|
+
`WORLDMESH_VERSION` tracks this package's version. `WORLDMESH_PROTOCOL` is a
|
|
69
|
+
separate integer that only changes when the world-facing contract changes in a
|
|
70
|
+
way a world would have to react to — see
|
|
71
|
+
[docs/publishing.md](https://github.com/eliaswillnat/worldmesh/blob/main/docs/publishing.md).
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import { WORLDMESH_PROTOCOL } from '@worldmesh/runtime';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Abilities } from '../types.js';
|
|
2
|
+
export declare const DEFAULT_ABILITIES: Abilities;
|
|
3
|
+
/**
|
|
4
|
+
* Merge a world's declared abilities over the defaults. Abilities are pure
|
|
5
|
+
* configuration: the shared controller reads these flags, so a world never
|
|
6
|
+
* has to fork the movement code to add one.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveAbilities(declared?: Partial<Abilities>): Abilities;
|
|
9
|
+
//# sourceMappingURL=abilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abilities.d.ts","sourceRoot":"","sources":["../../src/abilities/abilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,iBAAiB,EAAE,SAQ/B,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,OAAO,CAAC,SAAS,CAAM,GAAG,SAAS,CAU7E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const DEFAULT_ABILITIES = {
|
|
2
|
+
doubleJump: false,
|
|
3
|
+
flying: false,
|
|
4
|
+
crouching: false,
|
|
5
|
+
dash: false,
|
|
6
|
+
climbing: false,
|
|
7
|
+
swimming: false,
|
|
8
|
+
vehicles: false,
|
|
9
|
+
};
|
|
10
|
+
const RESERVED = ['climbing', 'swimming', 'vehicles'];
|
|
11
|
+
/**
|
|
12
|
+
* Merge a world's declared abilities over the defaults. Abilities are pure
|
|
13
|
+
* configuration: the shared controller reads these flags, so a world never
|
|
14
|
+
* has to fork the movement code to add one.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveAbilities(declared = {}) {
|
|
17
|
+
const abilities = { ...DEFAULT_ABILITIES, ...declared };
|
|
18
|
+
for (const key of RESERVED) {
|
|
19
|
+
if (abilities[key]) {
|
|
20
|
+
console.warn(`[worldmesh] ability "${key}" is reserved in the standard but not implemented yet; it will have no effect.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return abilities;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=abilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abilities.js","sourceRoot":"","sources":["../../src/abilities/abilities.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,KAAK;IACX,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;CAChB,CAAC;AAEF,MAAM,QAAQ,GAAwB,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAA+B,EAAE;IAChE,MAAM,SAAS,GAAc,EAAE,GAAG,iBAAiB,EAAE,GAAG,QAAQ,EAAE,CAAC;IACnE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CACV,wBAAwB,GAAG,gFAAgF,CAC5G,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Vector3, type Camera } from 'three';
|
|
2
|
+
import type { CollisionWorld } from '../movement/collision.js';
|
|
3
|
+
import type { ViewMode, ViewOptions } from '../types.js';
|
|
4
|
+
export interface CameraRigOptions extends ViewOptions {
|
|
5
|
+
camera: Camera;
|
|
6
|
+
collision: CollisionWorld;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Owns yaw/pitch and both camera modes. Worlds get first- and third-person
|
|
10
|
+
* for free, with the same toggle key everywhere, because this lives in the
|
|
11
|
+
* runtime rather than in each world's main.ts.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CameraRig {
|
|
14
|
+
yaw: number;
|
|
15
|
+
pitch: number;
|
|
16
|
+
mode: ViewMode;
|
|
17
|
+
distance: number;
|
|
18
|
+
sensitivity: number;
|
|
19
|
+
private camera;
|
|
20
|
+
private collision;
|
|
21
|
+
private minDistance;
|
|
22
|
+
private maxDistance;
|
|
23
|
+
private euler;
|
|
24
|
+
private target;
|
|
25
|
+
private offset;
|
|
26
|
+
/** Smoothed boom length so the camera does not pop when it clears a wall. */
|
|
27
|
+
private currentBoom;
|
|
28
|
+
constructor(options: CameraRigOptions);
|
|
29
|
+
look(dx: number, dy: number): void;
|
|
30
|
+
zoom(wheel: number): void;
|
|
31
|
+
setMode(mode: ViewMode): void;
|
|
32
|
+
toggleMode(): ViewMode;
|
|
33
|
+
/** Point the camera at the player. `feet` is the player's base position. */
|
|
34
|
+
update(dt: number, feet: Vector3, eyeHeight: number): void;
|
|
35
|
+
/** Horizontal forward vector, for spawn orientation helpers. */
|
|
36
|
+
getForward(out?: Vector3): Vector3;
|
|
37
|
+
resize(width: number, height: number): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cameraRig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cameraRig.d.ts","sourceRoot":"","sources":["../../src/camera/cameraRig.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,OAAO,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAKzD,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED;;;;GAIG;AACH,qBAAa,SAAS;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAAiB;IAC/B,6EAA6E;IAC7E,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,gBAAgB;IAarC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAMlC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAK7B,UAAU,IAAI,QAAQ;IAKtB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAqB1D,gEAAgE;IAChE,UAAU,CAAC,GAAG,UAAgB,GAAG,OAAO;IAIxC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAM5C"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Euler, PerspectiveCamera, Vector3 } from 'three';
|
|
2
|
+
const HALF_PI = Math.PI / 2;
|
|
3
|
+
const PITCH_LIMIT = HALF_PI - 0.01;
|
|
4
|
+
/**
|
|
5
|
+
* Owns yaw/pitch and both camera modes. Worlds get first- and third-person
|
|
6
|
+
* for free, with the same toggle key everywhere, because this lives in the
|
|
7
|
+
* runtime rather than in each world's main.ts.
|
|
8
|
+
*/
|
|
9
|
+
export class CameraRig {
|
|
10
|
+
yaw;
|
|
11
|
+
pitch;
|
|
12
|
+
mode;
|
|
13
|
+
distance;
|
|
14
|
+
sensitivity;
|
|
15
|
+
camera;
|
|
16
|
+
collision;
|
|
17
|
+
minDistance;
|
|
18
|
+
maxDistance;
|
|
19
|
+
euler = new Euler(0, 0, 0, 'YXZ');
|
|
20
|
+
target = new Vector3();
|
|
21
|
+
offset = new Vector3();
|
|
22
|
+
/** Smoothed boom length so the camera does not pop when it clears a wall. */
|
|
23
|
+
currentBoom;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.camera = options.camera;
|
|
26
|
+
this.collision = options.collision;
|
|
27
|
+
this.mode = options.mode ?? 'first';
|
|
28
|
+
this.distance = options.distance ?? 5;
|
|
29
|
+
this.currentBoom = this.distance;
|
|
30
|
+
this.minDistance = options.minDistance ?? 2;
|
|
31
|
+
this.maxDistance = options.maxDistance ?? 12;
|
|
32
|
+
this.sensitivity = options.sensitivity ?? 0.0022;
|
|
33
|
+
this.yaw = options.yaw ?? 0;
|
|
34
|
+
this.pitch = options.pitch ?? 0;
|
|
35
|
+
}
|
|
36
|
+
look(dx, dy) {
|
|
37
|
+
this.yaw -= dx * this.sensitivity;
|
|
38
|
+
this.pitch -= dy * this.sensitivity;
|
|
39
|
+
this.pitch = Math.max(-PITCH_LIMIT, Math.min(PITCH_LIMIT, this.pitch));
|
|
40
|
+
}
|
|
41
|
+
zoom(wheel) {
|
|
42
|
+
if (this.mode !== 'third' || wheel === 0)
|
|
43
|
+
return;
|
|
44
|
+
this.distance = clamp(this.distance + wheel * 0.01, this.minDistance, this.maxDistance);
|
|
45
|
+
}
|
|
46
|
+
setMode(mode) {
|
|
47
|
+
this.mode = mode;
|
|
48
|
+
if (mode === 'third')
|
|
49
|
+
this.currentBoom = this.distance;
|
|
50
|
+
}
|
|
51
|
+
toggleMode() {
|
|
52
|
+
this.setMode(this.mode === 'first' ? 'third' : 'first');
|
|
53
|
+
return this.mode;
|
|
54
|
+
}
|
|
55
|
+
/** Point the camera at the player. `feet` is the player's base position. */
|
|
56
|
+
update(dt, feet, eyeHeight) {
|
|
57
|
+
this.euler.set(this.pitch, this.yaw, 0);
|
|
58
|
+
this.camera.quaternion.setFromEuler(this.euler);
|
|
59
|
+
this.target.set(feet.x, feet.y + eyeHeight, feet.z);
|
|
60
|
+
if (this.mode === 'first') {
|
|
61
|
+
this.camera.position.copy(this.target);
|
|
62
|
+
this.currentBoom = this.distance;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Boom backwards along the view direction, pulled in by anything in the way.
|
|
66
|
+
this.offset.set(0, 0, 1).applyQuaternion(this.camera.quaternion);
|
|
67
|
+
const wanted = this.collision.castDistance(this.target, this.offset, this.distance + 0.3) - 0.3;
|
|
68
|
+
const boom = clamp(wanted, 0.4, this.distance);
|
|
69
|
+
// Snap in fast, ease out slowly: popping into geometry is worse than lag.
|
|
70
|
+
const rate = boom < this.currentBoom ? 1 : 1 - Math.exp(-8 * dt);
|
|
71
|
+
this.currentBoom += (boom - this.currentBoom) * rate;
|
|
72
|
+
this.camera.position.copy(this.target).addScaledVector(this.offset, this.currentBoom);
|
|
73
|
+
}
|
|
74
|
+
/** Horizontal forward vector, for spawn orientation helpers. */
|
|
75
|
+
getForward(out = new Vector3()) {
|
|
76
|
+
return out.set(-Math.sin(this.yaw), 0, -Math.cos(this.yaw));
|
|
77
|
+
}
|
|
78
|
+
resize(width, height) {
|
|
79
|
+
if (this.camera instanceof PerspectiveCamera) {
|
|
80
|
+
this.camera.aspect = width / height;
|
|
81
|
+
this.camera.updateProjectionMatrix();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function clamp(value, min, max) {
|
|
86
|
+
return Math.max(min, Math.min(max, value));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=cameraRig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cameraRig.js","sourceRoot":"","sources":["../../src/camera/cameraRig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { InputAction, Keymap } from '../types.js';
|
|
2
|
+
export interface InputOptions {
|
|
3
|
+
/** The element that receives pointer lock. */
|
|
4
|
+
element: HTMLElement;
|
|
5
|
+
keymap?: Partial<Keymap>;
|
|
6
|
+
onPointerLockChange?: (locked: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Keyboard + pointer-lock mouse input with mobile touch controls support.
|
|
10
|
+
* This is the only place in WorldMesh that reads raw browser events, so the
|
|
11
|
+
* control convention lives in one file instead of being copy-pasted into every world.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Input {
|
|
14
|
+
readonly keymap: Keymap;
|
|
15
|
+
/** Accumulated mouse movement since the last read, in pixels. */
|
|
16
|
+
mouseDeltaX: number;
|
|
17
|
+
mouseDeltaY: number;
|
|
18
|
+
/** Accumulated wheel movement since the last read. */
|
|
19
|
+
wheelDelta: number;
|
|
20
|
+
locked: boolean;
|
|
21
|
+
private element;
|
|
22
|
+
private pressed;
|
|
23
|
+
/** Actions that went down this frame and have not been consumed yet. */
|
|
24
|
+
private justPressed;
|
|
25
|
+
/** The last number key pressed this frame, if any. */
|
|
26
|
+
private pendingDigit;
|
|
27
|
+
private codeToActions;
|
|
28
|
+
private onPointerLockChange?;
|
|
29
|
+
private touch?;
|
|
30
|
+
private disposed;
|
|
31
|
+
constructor(options: InputOptions);
|
|
32
|
+
requestPointerLock(touchTriggered?: boolean): void;
|
|
33
|
+
setLocked(locked: boolean): void;
|
|
34
|
+
exitPointerLock(): void;
|
|
35
|
+
triggerAction(action: InputAction): void;
|
|
36
|
+
isDown(action: InputAction): boolean;
|
|
37
|
+
/** True once per key press. Reading it clears the flag. */
|
|
38
|
+
consume(action: InputAction): boolean;
|
|
39
|
+
/** The number key (0–9) pressed this frame, once. Reading it clears it. */
|
|
40
|
+
consumeDigit(): number | null;
|
|
41
|
+
/** Movement intent on the local XZ plane, already normalized. */
|
|
42
|
+
getMoveAxis(): {
|
|
43
|
+
x: number;
|
|
44
|
+
z: number;
|
|
45
|
+
};
|
|
46
|
+
/** Read and reset the mouse/wheel/touch accumulators. Call once per frame. */
|
|
47
|
+
readLook(): {
|
|
48
|
+
dx: number;
|
|
49
|
+
dy: number;
|
|
50
|
+
wheel: number;
|
|
51
|
+
};
|
|
52
|
+
/** Drop stale edge-triggers at the end of a frame. */
|
|
53
|
+
endFrame(): void;
|
|
54
|
+
dispose(): void;
|
|
55
|
+
private handleKeyDown;
|
|
56
|
+
private handleKeyUp;
|
|
57
|
+
/** Losing focus must not leave a key stuck down. */
|
|
58
|
+
private handleBlur;
|
|
59
|
+
private handleMouseMove;
|
|
60
|
+
private handleWheel;
|
|
61
|
+
private handlePointerLockChange;
|
|
62
|
+
private handlePointerLockError;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/controls/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIvD,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD;AAED;;;;GAIG;AACH,qBAAa,KAAK;IAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,WAAW,SAAK;IAChB,WAAW,SAAK;IAChB,sDAAsD;IACtD,UAAU,SAAK;IACf,MAAM,UAAS;IAEf,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,OAAO,CAAqB;IACpC,wEAAwE;IACxE,OAAO,CAAC,WAAW,CAA0B;IAC7C,sDAAsD;IACtD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,mBAAmB,CAAC,CAA4B;IACxD,OAAO,CAAC,KAAK,CAAC,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,YAAY;IA+BjC,kBAAkB,CAAC,cAAc,UAAQ,GAAG,IAAI;IA4BhD,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAYhC,eAAe,IAAI,IAAI;IAOvB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIxC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO;IAMpC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO;IAOrC,2EAA2E;IAC3E,YAAY,IAAI,MAAM,GAAG,IAAI;IAM7B,iEAAiE;IACjE,WAAW,IAAI;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAgBvC,8EAA8E;IAC9E,QAAQ,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAerD,sDAAsD;IACtD,QAAQ,IAAI,IAAI;IAKhB,OAAO,IAAI,IAAI;IAcf,OAAO,CAAC,aAAa,CAcnB;IAEF,OAAO,CAAC,WAAW,CAEjB;IAEF,oDAAoD;IACpD,OAAO,CAAC,UAAU,CAGhB;IAEF,OAAO,CAAC,eAAe,CAIrB;IAEF,OAAO,CAAC,WAAW,CAGjB;IAEF,OAAO,CAAC,uBAAuB,CAQ7B;IAEF,OAAO,CAAC,sBAAsB,CAK5B;CACH"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { resolveKeymap } from './keymap.js';
|
|
2
|
+
import { TouchControls, isTouchDevice } from './touch.js';
|
|
3
|
+
/**
|
|
4
|
+
* Keyboard + pointer-lock mouse input with mobile touch controls support.
|
|
5
|
+
* This is the only place in WorldMesh that reads raw browser events, so the
|
|
6
|
+
* control convention lives in one file instead of being copy-pasted into every world.
|
|
7
|
+
*/
|
|
8
|
+
export class Input {
|
|
9
|
+
keymap;
|
|
10
|
+
/** Accumulated mouse movement since the last read, in pixels. */
|
|
11
|
+
mouseDeltaX = 0;
|
|
12
|
+
mouseDeltaY = 0;
|
|
13
|
+
/** Accumulated wheel movement since the last read. */
|
|
14
|
+
wheelDelta = 0;
|
|
15
|
+
locked = false;
|
|
16
|
+
element;
|
|
17
|
+
pressed = new Set();
|
|
18
|
+
/** Actions that went down this frame and have not been consumed yet. */
|
|
19
|
+
justPressed = new Set();
|
|
20
|
+
/** The last number key pressed this frame, if any. */
|
|
21
|
+
pendingDigit = null;
|
|
22
|
+
codeToActions = new Map();
|
|
23
|
+
onPointerLockChange;
|
|
24
|
+
touch;
|
|
25
|
+
disposed = false;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.element = options.element;
|
|
28
|
+
this.keymap = resolveKeymap(options.keymap);
|
|
29
|
+
this.onPointerLockChange = options.onPointerLockChange;
|
|
30
|
+
for (const action of Object.keys(this.keymap)) {
|
|
31
|
+
for (const code of this.keymap[action]) {
|
|
32
|
+
const list = this.codeToActions.get(code) ?? [];
|
|
33
|
+
list.push(action);
|
|
34
|
+
this.codeToActions.set(code, list);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Touch controls on mobile / touchscreens
|
|
38
|
+
this.element.style.touchAction = 'none';
|
|
39
|
+
if (typeof window !== 'undefined') {
|
|
40
|
+
this.touch = new TouchControls({
|
|
41
|
+
element: this.element,
|
|
42
|
+
onExit: () => this.exitPointerLock(),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
window.addEventListener('keydown', this.handleKeyDown);
|
|
46
|
+
window.addEventListener('keyup', this.handleKeyUp);
|
|
47
|
+
window.addEventListener('blur', this.handleBlur);
|
|
48
|
+
document.addEventListener('pointerlockchange', this.handlePointerLockChange);
|
|
49
|
+
document.addEventListener('pointerlockerror', this.handlePointerLockError);
|
|
50
|
+
this.element.addEventListener('mousemove', this.handleMouseMove);
|
|
51
|
+
this.element.addEventListener('wheel', this.handleWheel, { passive: true });
|
|
52
|
+
}
|
|
53
|
+
requestPointerLock(touchTriggered = false) {
|
|
54
|
+
if (this.disposed || this.locked)
|
|
55
|
+
return;
|
|
56
|
+
// Mobile / touch devices do not support pointer lock. Enter directly.
|
|
57
|
+
if (touchTriggered || isTouchDevice()) {
|
|
58
|
+
this.setLocked(true);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (typeof this.element.requestPointerLock === 'function') {
|
|
62
|
+
try {
|
|
63
|
+
const promise = this.element.requestPointerLock();
|
|
64
|
+
if (promise && typeof promise.then === 'function') {
|
|
65
|
+
promise.catch(() => {
|
|
66
|
+
// Pointer lock rejected (e.g. mobile Safari, tablet, iframe restrictions)
|
|
67
|
+
this.setLocked(true);
|
|
68
|
+
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
this.setLocked(true);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.setLocked(true);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
setLocked(locked) {
|
|
82
|
+
if (this.locked === locked)
|
|
83
|
+
return;
|
|
84
|
+
this.locked = locked;
|
|
85
|
+
if (!locked) {
|
|
86
|
+
this.pressed.clear();
|
|
87
|
+
this.justPressed.clear();
|
|
88
|
+
this.touch?.reset();
|
|
89
|
+
}
|
|
90
|
+
this.touch?.setVisible(locked && isTouchDevice());
|
|
91
|
+
this.onPointerLockChange?.(this.locked);
|
|
92
|
+
}
|
|
93
|
+
exitPointerLock() {
|
|
94
|
+
if (document.pointerLockElement === this.element) {
|
|
95
|
+
document.exitPointerLock();
|
|
96
|
+
}
|
|
97
|
+
this.setLocked(false);
|
|
98
|
+
}
|
|
99
|
+
triggerAction(action) {
|
|
100
|
+
this.justPressed.add(action);
|
|
101
|
+
}
|
|
102
|
+
isDown(action) {
|
|
103
|
+
if (this.touch?.isDown(action))
|
|
104
|
+
return true;
|
|
105
|
+
for (const code of this.keymap[action])
|
|
106
|
+
if (this.pressed.has(code))
|
|
107
|
+
return true;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
/** True once per key press. Reading it clears the flag. */
|
|
111
|
+
consume(action) {
|
|
112
|
+
if (this.touch?.consume(action))
|
|
113
|
+
return true;
|
|
114
|
+
if (!this.justPressed.has(action))
|
|
115
|
+
return false;
|
|
116
|
+
this.justPressed.delete(action);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
/** The number key (0–9) pressed this frame, once. Reading it clears it. */
|
|
120
|
+
consumeDigit() {
|
|
121
|
+
const digit = this.pendingDigit;
|
|
122
|
+
this.pendingDigit = null;
|
|
123
|
+
return digit;
|
|
124
|
+
}
|
|
125
|
+
/** Movement intent on the local XZ plane, already normalized. */
|
|
126
|
+
getMoveAxis() {
|
|
127
|
+
let x = (this.isDown('right') ? 1 : 0) - (this.isDown('left') ? 1 : 0);
|
|
128
|
+
let z = (this.isDown('backward') ? 1 : 0) - (this.isDown('forward') ? 1 : 0);
|
|
129
|
+
if (this.touch) {
|
|
130
|
+
const touchAxis = this.touch.getMoveAxis();
|
|
131
|
+
x += touchAxis.x;
|
|
132
|
+
z += touchAxis.z;
|
|
133
|
+
}
|
|
134
|
+
const length = Math.hypot(x, z);
|
|
135
|
+
if (length === 0)
|
|
136
|
+
return { x: 0, z: 0 };
|
|
137
|
+
if (length > 1)
|
|
138
|
+
return { x: x / length, z: z / length };
|
|
139
|
+
return { x, z };
|
|
140
|
+
}
|
|
141
|
+
/** Read and reset the mouse/wheel/touch accumulators. Call once per frame. */
|
|
142
|
+
readLook() {
|
|
143
|
+
let dx = this.mouseDeltaX;
|
|
144
|
+
let dy = this.mouseDeltaY;
|
|
145
|
+
if (this.touch) {
|
|
146
|
+
const touchLook = this.touch.readLook();
|
|
147
|
+
dx += touchLook.dx;
|
|
148
|
+
dy += touchLook.dy;
|
|
149
|
+
}
|
|
150
|
+
const look = { dx, dy, wheel: this.wheelDelta };
|
|
151
|
+
this.mouseDeltaX = 0;
|
|
152
|
+
this.mouseDeltaY = 0;
|
|
153
|
+
this.wheelDelta = 0;
|
|
154
|
+
return look;
|
|
155
|
+
}
|
|
156
|
+
/** Drop stale edge-triggers at the end of a frame. */
|
|
157
|
+
endFrame() {
|
|
158
|
+
this.justPressed.clear();
|
|
159
|
+
this.pendingDigit = null;
|
|
160
|
+
}
|
|
161
|
+
dispose() {
|
|
162
|
+
this.disposed = true;
|
|
163
|
+
this.touch?.dispose();
|
|
164
|
+
window.removeEventListener('keydown', this.handleKeyDown);
|
|
165
|
+
window.removeEventListener('keyup', this.handleKeyUp);
|
|
166
|
+
window.removeEventListener('blur', this.handleBlur);
|
|
167
|
+
document.removeEventListener('pointerlockchange', this.handlePointerLockChange);
|
|
168
|
+
document.removeEventListener('pointerlockerror', this.handlePointerLockError);
|
|
169
|
+
this.element.removeEventListener('mousemove', this.handleMouseMove);
|
|
170
|
+
this.element.removeEventListener('wheel', this.handleWheel);
|
|
171
|
+
this.pressed.clear();
|
|
172
|
+
this.justPressed.clear();
|
|
173
|
+
}
|
|
174
|
+
handleKeyDown = (event) => {
|
|
175
|
+
if (event.repeat)
|
|
176
|
+
return;
|
|
177
|
+
if (isTypingTarget(event.target))
|
|
178
|
+
return;
|
|
179
|
+
const actions = this.codeToActions.get(event.code);
|
|
180
|
+
if (!actions) {
|
|
181
|
+
// Unbound number keys pick a face for the avatar.
|
|
182
|
+
const digit = /^(?:Digit|Numpad)(\d)$/.exec(event.code);
|
|
183
|
+
if (digit)
|
|
184
|
+
this.pendingDigit = Number(digit[1]);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Space and the arrow keys scroll the page otherwise.
|
|
188
|
+
if (event.code === 'Space' || event.code.startsWith('Arrow'))
|
|
189
|
+
event.preventDefault();
|
|
190
|
+
this.pressed.add(event.code);
|
|
191
|
+
for (const action of actions)
|
|
192
|
+
this.justPressed.add(action);
|
|
193
|
+
};
|
|
194
|
+
handleKeyUp = (event) => {
|
|
195
|
+
this.pressed.delete(event.code);
|
|
196
|
+
};
|
|
197
|
+
/** Losing focus must not leave a key stuck down. */
|
|
198
|
+
handleBlur = () => {
|
|
199
|
+
this.pressed.clear();
|
|
200
|
+
this.justPressed.clear();
|
|
201
|
+
};
|
|
202
|
+
handleMouseMove = (event) => {
|
|
203
|
+
if (!this.locked)
|
|
204
|
+
return;
|
|
205
|
+
this.mouseDeltaX += event.movementX;
|
|
206
|
+
this.mouseDeltaY += event.movementY;
|
|
207
|
+
};
|
|
208
|
+
handleWheel = (event) => {
|
|
209
|
+
if (!this.locked)
|
|
210
|
+
return;
|
|
211
|
+
this.wheelDelta += event.deltaY;
|
|
212
|
+
};
|
|
213
|
+
handlePointerLockChange = () => {
|
|
214
|
+
const isLocked = document.pointerLockElement === this.element;
|
|
215
|
+
if (isLocked) {
|
|
216
|
+
this.setLocked(true);
|
|
217
|
+
}
|
|
218
|
+
else if (!isTouchDevice()) {
|
|
219
|
+
// On non-touch desktop, losing pointer lock releases controls
|
|
220
|
+
this.setLocked(false);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
handlePointerLockError = () => {
|
|
224
|
+
// If pointer lock failed on desktop / iframe, still let the user enter
|
|
225
|
+
if (!this.locked) {
|
|
226
|
+
this.setLocked(true);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function isTypingTarget(target) {
|
|
231
|
+
if (!(target instanceof HTMLElement))
|
|
232
|
+
return false;
|
|
233
|
+
const tag = target.tagName;
|
|
234
|
+
return tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/controls/input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Keymap } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The WorldMesh control convention. Every world ships these bindings so that
|
|
4
|
+
* moving through an unfamiliar world feels like moving through a familiar one.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_KEYMAP: Keymap;
|
|
7
|
+
export declare function resolveKeymap(overrides?: Partial<Keymap>): Keymap;
|
|
8
|
+
//# sourceMappingURL=keymap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keymap.d.ts","sourceRoot":"","sources":["../../src/controls/keymap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,MAY5B,CAAC;AAEF,wBAAgB,aAAa,CAAC,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAAG,MAAM,CAErE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WorldMesh control convention. Every world ships these bindings so that
|
|
3
|
+
* moving through an unfamiliar world feels like moving through a familiar one.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_KEYMAP = {
|
|
6
|
+
forward: ['KeyW', 'ArrowUp'],
|
|
7
|
+
backward: ['KeyS', 'ArrowDown'],
|
|
8
|
+
left: ['KeyA', 'ArrowLeft'],
|
|
9
|
+
right: ['KeyD', 'ArrowRight'],
|
|
10
|
+
jump: ['Space'],
|
|
11
|
+
sprint: ['ShiftLeft', 'ShiftRight'],
|
|
12
|
+
interact: ['KeyE'],
|
|
13
|
+
toggleView: ['KeyV'],
|
|
14
|
+
crouch: ['KeyC'],
|
|
15
|
+
fly: ['KeyF'],
|
|
16
|
+
dash: ['KeyQ'],
|
|
17
|
+
};
|
|
18
|
+
export function resolveKeymap(overrides = {}) {
|
|
19
|
+
return { ...DEFAULT_KEYMAP, ...overrides };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=keymap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keymap.js","sourceRoot":"","sources":["../../src/controls/keymap.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,OAAO,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;IAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;IAC/B,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;IAC3B,KAAK,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,OAAO,CAAC;IACf,MAAM,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,CAAC;IAClB,UAAU,EAAE,CAAC,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,MAAM,CAAC;IAChB,GAAG,EAAE,CAAC,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,YAA6B,EAAE;IAC3D,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,SAAS,EAAE,CAAC;AAC7C,CAAC"}
|