@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
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AdditiveBlending,
|
|
3
|
+
CircleGeometry,
|
|
4
|
+
Color,
|
|
5
|
+
DoubleSide,
|
|
6
|
+
Group,
|
|
7
|
+
Mesh,
|
|
8
|
+
MeshBasicMaterial,
|
|
9
|
+
Object3D,
|
|
10
|
+
Scene,
|
|
11
|
+
TorusGeometry,
|
|
12
|
+
Vector3,
|
|
13
|
+
} from 'three';
|
|
14
|
+
import type { PortalMode, PortalOptions } from '../types.js';
|
|
15
|
+
|
|
16
|
+
export interface ResolvedPortal extends PortalOptions {
|
|
17
|
+
label: string;
|
|
18
|
+
radius: number;
|
|
19
|
+
mode: PortalMode;
|
|
20
|
+
object: Object3D | null;
|
|
21
|
+
center: Vector3;
|
|
22
|
+
inside: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Portals are the link element of the spatial web. For the MVP "following a
|
|
27
|
+
* link" is literally a page navigation to the destination world's own URL —
|
|
28
|
+
* WorldMesh hosts nothing about the destination. A `from` parameter is added
|
|
29
|
+
* so the destination knows where the visitor came from; state handoff and
|
|
30
|
+
* transitions can be layered on later without changing the world-side API.
|
|
31
|
+
*/
|
|
32
|
+
export class PortalManager {
|
|
33
|
+
private portals: ResolvedPortal[] = [];
|
|
34
|
+
private scene: Scene;
|
|
35
|
+
private group = new Group();
|
|
36
|
+
|
|
37
|
+
constructor(scene: Scene, portals: PortalOptions[] = []) {
|
|
38
|
+
this.scene = scene;
|
|
39
|
+
this.group.name = 'worldmesh:portals';
|
|
40
|
+
this.scene.add(this.group);
|
|
41
|
+
for (const portal of portals) this.add(portal);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get all(): readonly ResolvedPortal[] {
|
|
45
|
+
return this.portals;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
add(options: PortalOptions): ResolvedPortal {
|
|
49
|
+
const resolved: ResolvedPortal = {
|
|
50
|
+
...options,
|
|
51
|
+
label: options.label ?? hostLabel(options.url),
|
|
52
|
+
radius: options.radius ?? 2,
|
|
53
|
+
mode: options.mode ?? 'interact',
|
|
54
|
+
object: null,
|
|
55
|
+
center: new Vector3(...options.position),
|
|
56
|
+
inside: false,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (options.visual !== false) {
|
|
60
|
+
const visual = options.visual ?? createPortalVisual(resolved.radius, options.color ?? 0x6cf0ff);
|
|
61
|
+
visual.position.copy(resolved.center);
|
|
62
|
+
this.group.add(visual);
|
|
63
|
+
resolved.object = visual;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.portals.push(resolved);
|
|
67
|
+
return resolved;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Nearest portal the player is standing in, if any. */
|
|
71
|
+
findActive(feet: Vector3): ResolvedPortal | null {
|
|
72
|
+
let best: ResolvedPortal | null = null;
|
|
73
|
+
let bestDistance = Infinity;
|
|
74
|
+
for (const portal of this.portals) {
|
|
75
|
+
const distance = feet.distanceTo(portal.center);
|
|
76
|
+
// Generous vertical tolerance: the trigger is a stubby cylinder.
|
|
77
|
+
const withinHeight = Math.abs(feet.y - portal.center.y) < portal.radius + 2;
|
|
78
|
+
const active = distance < portal.radius && withinHeight;
|
|
79
|
+
portal.inside = active;
|
|
80
|
+
if (active && distance < bestDistance) {
|
|
81
|
+
best = portal;
|
|
82
|
+
bestDistance = distance;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return best;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
animate(elapsed: number): void {
|
|
89
|
+
for (const portal of this.portals) {
|
|
90
|
+
if (!portal.object) continue;
|
|
91
|
+
portal.object.rotation.y = elapsed * 0.4;
|
|
92
|
+
portal.object.position.y = portal.center.y + Math.sin(elapsed * 1.2) * 0.08;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
dispose(): void {
|
|
97
|
+
this.group.traverse((child) => {
|
|
98
|
+
if (child instanceof Mesh) {
|
|
99
|
+
child.geometry.dispose();
|
|
100
|
+
const material = child.material;
|
|
101
|
+
if (Array.isArray(material)) material.forEach((m) => m.dispose());
|
|
102
|
+
else material.dispose();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
this.scene.remove(this.group);
|
|
106
|
+
this.portals = [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Build the destination URL, carrying a back-reference to this world. */
|
|
111
|
+
export function buildTravelUrl(target: string): string {
|
|
112
|
+
try {
|
|
113
|
+
const url = new URL(target, window.location.href);
|
|
114
|
+
if (!url.searchParams.has('from')) {
|
|
115
|
+
url.searchParams.set('from', window.location.origin + window.location.pathname);
|
|
116
|
+
}
|
|
117
|
+
return url.toString();
|
|
118
|
+
} catch {
|
|
119
|
+
return target;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Where the visitor came from, if they arrived through a portal. */
|
|
124
|
+
export function getReferringWorld(): string | null {
|
|
125
|
+
const from = new URLSearchParams(window.location.search).get('from');
|
|
126
|
+
return from && /^https?:\/\//.test(from) ? from : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function createPortalVisual(radius: number, color: number | string): Object3D {
|
|
130
|
+
const group = new Group();
|
|
131
|
+
const tint = new Color(color);
|
|
132
|
+
|
|
133
|
+
const ring = new Mesh(
|
|
134
|
+
new TorusGeometry(radius * 0.9, radius * 0.08, 10, 40),
|
|
135
|
+
new MeshBasicMaterial({ color: tint }),
|
|
136
|
+
);
|
|
137
|
+
ring.rotation.x = Math.PI / 2;
|
|
138
|
+
ring.position.y = 0.05;
|
|
139
|
+
group.add(ring);
|
|
140
|
+
|
|
141
|
+
const glow = new Mesh(
|
|
142
|
+
new CircleGeometry(radius * 0.9, 32),
|
|
143
|
+
new MeshBasicMaterial({
|
|
144
|
+
color: tint,
|
|
145
|
+
transparent: true,
|
|
146
|
+
opacity: 0.22,
|
|
147
|
+
side: DoubleSide,
|
|
148
|
+
blending: AdditiveBlending,
|
|
149
|
+
depthWrite: false,
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
glow.rotation.x = -Math.PI / 2;
|
|
153
|
+
glow.position.y = 0.06;
|
|
154
|
+
group.add(glow);
|
|
155
|
+
|
|
156
|
+
const pillar = new Mesh(
|
|
157
|
+
new TorusGeometry(radius * 0.55, radius * 0.04, 8, 32),
|
|
158
|
+
new MeshBasicMaterial({ color: tint, transparent: true, opacity: 0.7 }),
|
|
159
|
+
);
|
|
160
|
+
pillar.rotation.x = Math.PI / 2;
|
|
161
|
+
pillar.position.y = radius * 1.2;
|
|
162
|
+
group.add(pillar);
|
|
163
|
+
|
|
164
|
+
return group;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function hostLabel(url: string): string {
|
|
168
|
+
try {
|
|
169
|
+
return new URL(url, window.location.href).host;
|
|
170
|
+
} catch {
|
|
171
|
+
return url;
|
|
172
|
+
}
|
|
173
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { AvatarExpression } from './player/avatar.js';
|
|
2
|
+
import type { Camera, Object3D, PerspectiveCamera, Scene, WebGLRenderer } from 'three';
|
|
3
|
+
|
|
4
|
+
export type Vec3Tuple = [number, number, number];
|
|
5
|
+
|
|
6
|
+
/** Camera modes every WorldMesh world supports. */
|
|
7
|
+
export type ViewMode = 'first' | 'third';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Optional movement capabilities. A world declares what it allows;
|
|
11
|
+
* the shared controller implements it. Worlds never rewrite the controller.
|
|
12
|
+
*
|
|
13
|
+
* `climbing`, `swimming` and `vehicles` are reserved: they are part of the
|
|
14
|
+
* standard's vocabulary but are not implemented yet, so enabling one logs a
|
|
15
|
+
* notice instead of silently doing nothing.
|
|
16
|
+
*/
|
|
17
|
+
export interface Abilities {
|
|
18
|
+
/** One extra jump while airborne. */
|
|
19
|
+
doubleJump: boolean;
|
|
20
|
+
/** Toggle free-flight with the fly key (default F). */
|
|
21
|
+
flying: boolean;
|
|
22
|
+
/** Hold crouch key (default C) to lower the player and slow down. */
|
|
23
|
+
crouching: boolean;
|
|
24
|
+
/** Burst of speed in the input direction (default Q). */
|
|
25
|
+
dash: boolean;
|
|
26
|
+
/** Reserved — not implemented yet. */
|
|
27
|
+
climbing: boolean;
|
|
28
|
+
/** Reserved — not implemented yet. */
|
|
29
|
+
swimming: boolean;
|
|
30
|
+
/** Reserved — not implemented yet. */
|
|
31
|
+
vehicles: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Every logical action the runtime understands, mapped to KeyboardEvent.code values. */
|
|
35
|
+
export interface Keymap {
|
|
36
|
+
forward: string[];
|
|
37
|
+
backward: string[];
|
|
38
|
+
left: string[];
|
|
39
|
+
right: string[];
|
|
40
|
+
jump: string[];
|
|
41
|
+
sprint: string[];
|
|
42
|
+
interact: string[];
|
|
43
|
+
toggleView: string[];
|
|
44
|
+
crouch: string[];
|
|
45
|
+
fly: string[];
|
|
46
|
+
dash: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type InputAction = keyof Keymap;
|
|
50
|
+
|
|
51
|
+
export interface MovementTuning {
|
|
52
|
+
walkSpeed: number;
|
|
53
|
+
sprintSpeed: number;
|
|
54
|
+
crouchSpeed: number;
|
|
55
|
+
flySpeed: number;
|
|
56
|
+
jumpSpeed: number;
|
|
57
|
+
gravity: number;
|
|
58
|
+
/** How fast ground velocity approaches the target (1/s). */
|
|
59
|
+
groundAccel: number;
|
|
60
|
+
/** How fast air velocity approaches the target (1/s). */
|
|
61
|
+
airAccel: number;
|
|
62
|
+
dashSpeed: number;
|
|
63
|
+
dashCooldown: number;
|
|
64
|
+
/** Terminal falling speed. */
|
|
65
|
+
maxFallSpeed: number;
|
|
66
|
+
/** Anything below this Y counts as "fell out of the world" and respawns. */
|
|
67
|
+
fallLimit: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface PlayerOptions {
|
|
71
|
+
/** Total standing height in metres. */
|
|
72
|
+
height?: number;
|
|
73
|
+
/** Collision radius in metres. */
|
|
74
|
+
radius?: number;
|
|
75
|
+
/** Eye offset from the feet in metres. Defaults to height - 0.2. */
|
|
76
|
+
eyeHeight?: number;
|
|
77
|
+
/** Replace the default white figure, or pass `false` for no avatar at all. */
|
|
78
|
+
avatar?: Object3D | false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface ViewOptions {
|
|
82
|
+
mode?: ViewMode;
|
|
83
|
+
/** Third-person boom length in metres. */
|
|
84
|
+
distance?: number;
|
|
85
|
+
minDistance?: number;
|
|
86
|
+
maxDistance?: number;
|
|
87
|
+
/** Mouse sensitivity, radians per pixel. */
|
|
88
|
+
sensitivity?: number;
|
|
89
|
+
/** Start looking along this yaw, in radians. 0 looks down -Z. */
|
|
90
|
+
yaw?: number;
|
|
91
|
+
pitch?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type PortalMode = 'interact' | 'auto';
|
|
95
|
+
|
|
96
|
+
export interface PortalOptions {
|
|
97
|
+
/** Destination world URL. Absolute, on the destination's own host. */
|
|
98
|
+
url: string;
|
|
99
|
+
/** Human label shown in the interact prompt. */
|
|
100
|
+
label?: string;
|
|
101
|
+
position: Vec3Tuple;
|
|
102
|
+
/** Trigger radius in metres. */
|
|
103
|
+
radius?: number;
|
|
104
|
+
/** `interact` (press E) or `auto` (walk through). Defaults to `interact`. */
|
|
105
|
+
mode?: PortalMode;
|
|
106
|
+
color?: number | string;
|
|
107
|
+
/** Skip the built-in ring mesh and use the world's own geometry. */
|
|
108
|
+
visual?: Object3D | false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface UiOptions {
|
|
112
|
+
/** Crosshair dot in first person. */
|
|
113
|
+
crosshair?: boolean;
|
|
114
|
+
/** Bottom-left WorldMesh badge linking back to the hub. */
|
|
115
|
+
badge?: boolean;
|
|
116
|
+
/** Where the badge links. */
|
|
117
|
+
hubUrl?: string;
|
|
118
|
+
/** Click-to-enter overlay and the shared controls legend. */
|
|
119
|
+
controlsHint?: boolean;
|
|
120
|
+
/** World name shown in the overlay. */
|
|
121
|
+
title?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Everything another peer would need to draw this player. Serializable on purpose. */
|
|
125
|
+
export interface PlayerState {
|
|
126
|
+
position: Vec3Tuple;
|
|
127
|
+
velocity: Vec3Tuple;
|
|
128
|
+
yaw: number;
|
|
129
|
+
pitch: number;
|
|
130
|
+
/** Where the body faces; in third person it can differ from the camera's yaw. */
|
|
131
|
+
facing: number;
|
|
132
|
+
onGround: boolean;
|
|
133
|
+
crouching: boolean;
|
|
134
|
+
flying: boolean;
|
|
135
|
+
/** The face the default figure is pulling, picked with the number keys. */
|
|
136
|
+
expression: AvatarExpression;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface WorldMeshEvents {
|
|
140
|
+
/** Fired every simulation step, after movement resolves. */
|
|
141
|
+
update: { dt: number; state: PlayerState };
|
|
142
|
+
/** Player crossed into a portal trigger. */
|
|
143
|
+
'portal:enter': { portal: PortalOptions };
|
|
144
|
+
'portal:exit': { portal: PortalOptions };
|
|
145
|
+
/** Navigation is about to happen. Call `preventDefault()` to take over. */
|
|
146
|
+
'portal:activate': { portal: PortalOptions; url: string; preventDefault(): void };
|
|
147
|
+
'view:change': { mode: ViewMode };
|
|
148
|
+
'pointer:lock': { locked: boolean };
|
|
149
|
+
/** E pressed with nothing else claiming it. */
|
|
150
|
+
interact: { position: Vec3Tuple };
|
|
151
|
+
respawn: { reason: 'fell' | 'manual' };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Multiplayer seam. Nothing in the runtime implements this yet — it exists so
|
|
156
|
+
* the local player loop stays shaped like something a network can drive later
|
|
157
|
+
* (peer-to-peer, a world-hosted server, or a WorldMesh signaling service).
|
|
158
|
+
*/
|
|
159
|
+
export interface NetworkAdapter {
|
|
160
|
+
/** Called once with a read-only view of the local world. */
|
|
161
|
+
attach(world: WorldMeshHandle): void;
|
|
162
|
+
/** Called with the local player's state at the network tick rate. */
|
|
163
|
+
sendLocalState?(state: PlayerState): void;
|
|
164
|
+
/** Called by the adapter when a remote peer's state arrives. */
|
|
165
|
+
onRemoteState?(peerId: string, state: PlayerState): void;
|
|
166
|
+
detach?(): void;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface WorldMeshOptions {
|
|
170
|
+
scene: Scene;
|
|
171
|
+
camera: Camera | PerspectiveCamera;
|
|
172
|
+
renderer: WebGLRenderer;
|
|
173
|
+
/** Where the player starts. Defaults to [0, 2, 0]. */
|
|
174
|
+
spawn?: Vec3Tuple;
|
|
175
|
+
abilities?: Partial<Abilities>;
|
|
176
|
+
/**
|
|
177
|
+
* Meshes the player can stand on and bump into. Pass a function if the world
|
|
178
|
+
* builds geometry lazily. Empty means "flat ground at spawn Y level 0".
|
|
179
|
+
*/
|
|
180
|
+
colliders?: Object3D[] | (() => Object3D[]);
|
|
181
|
+
portals?: PortalOptions[];
|
|
182
|
+
player?: PlayerOptions;
|
|
183
|
+
view?: ViewOptions;
|
|
184
|
+
keymap?: Partial<Keymap>;
|
|
185
|
+
movement?: Partial<MovementTuning>;
|
|
186
|
+
ui?: UiOptions;
|
|
187
|
+
/** Ground plane height used when a world provides no colliders. */
|
|
188
|
+
groundLevel?: number;
|
|
189
|
+
/** Run the render loop for you. Defaults to true. */
|
|
190
|
+
autoStart?: boolean;
|
|
191
|
+
/** Handle resize for you (camera aspect + renderer size). Defaults to true. */
|
|
192
|
+
autoResize?: boolean;
|
|
193
|
+
/** Your per-frame world logic. Runs after movement, before rendering. */
|
|
194
|
+
onUpdate?: (dt: number, world: WorldMeshHandle) => void;
|
|
195
|
+
/** Reserved. Not used by the MVP. */
|
|
196
|
+
network?: NetworkAdapter;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface WorldMeshHandle {
|
|
200
|
+
readonly scene: Scene;
|
|
201
|
+
readonly camera: Camera;
|
|
202
|
+
readonly renderer: WebGLRenderer;
|
|
203
|
+
readonly abilities: Readonly<Abilities>;
|
|
204
|
+
/** The avatar root. Move it and you move the player. */
|
|
205
|
+
readonly avatar: Object3D | null;
|
|
206
|
+
|
|
207
|
+
start(): void;
|
|
208
|
+
stop(): void;
|
|
209
|
+
/** Advance the simulation by `dt` seconds without rendering. */
|
|
210
|
+
update(dt: number): void;
|
|
211
|
+
dispose(): void;
|
|
212
|
+
|
|
213
|
+
getState(): PlayerState;
|
|
214
|
+
setState(state: Partial<PlayerState>): void;
|
|
215
|
+
teleport(position: Vec3Tuple, yaw?: number): void;
|
|
216
|
+
respawn(): void;
|
|
217
|
+
|
|
218
|
+
setViewMode(mode: ViewMode): void;
|
|
219
|
+
getViewMode(): ViewMode;
|
|
220
|
+
|
|
221
|
+
addPortal(portal: PortalOptions): void;
|
|
222
|
+
/** Navigate to another WorldMesh world, carrying a `from` back-reference. */
|
|
223
|
+
travelTo(url: string): void;
|
|
224
|
+
|
|
225
|
+
on<K extends keyof WorldMeshEvents>(event: K, fn: (payload: WorldMeshEvents[K]) => void): () => void;
|
|
226
|
+
off<K extends keyof WorldMeshEvents>(event: K, fn: (payload: WorldMeshEvents[K]) => void): void;
|
|
227
|
+
|
|
228
|
+
/** Refresh the collider list after the world adds geometry. */
|
|
229
|
+
refreshColliders(): void;
|
|
230
|
+
}
|