@relu-interactives/spatial-ecs 0.9.0 → 0.11.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 (39) hide show
  1. package/dist/{System-8D-XBDKZ.d.cts → System-BldSHxZV.d.cts} +214 -81
  2. package/dist/{System-DPMAW30g.d.ts → System-CADhPyQs.d.ts} +214 -81
  3. package/dist/{XRHandPose-CWSrsnYN.d.ts → XRHandPose-BNSwd1y9.d.ts} +1 -1
  4. package/dist/{XRHandPose-Dn2yiALk.d.cts → XRHandPose-D3Ab1Dfs.d.cts} +1 -1
  5. package/dist/{chunk-VYIWOXAY.js → chunk-TY3XCHOR.js} +18 -10
  6. package/dist/chunk-TY3XCHOR.js.map +1 -0
  7. package/dist/components/index.d.cts +3 -3
  8. package/dist/components/index.d.ts +3 -3
  9. package/dist/docs/guide/bone-attachments-and-ik.md +1 -1
  10. package/dist/docs/guide/multiplayer.md +65 -0
  11. package/dist/factories/index.d.cts +2 -2
  12. package/dist/factories/index.d.ts +2 -2
  13. package/dist/{index-D5MmJNyj.d.ts → index-6pZO_gV7.d.ts} +1 -1
  14. package/dist/{index-CAZHrh0q.d.cts → index-BXjwEdNq.d.cts} +2 -2
  15. package/dist/{index-DiIjV2lm.d.cts → index-BdghvXKE.d.cts} +1 -1
  16. package/dist/{index-CLtSMf2M.d.ts → index-CVG-hREM.d.ts} +2 -2
  17. package/dist/index.cjs +16 -8
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +8 -30
  20. package/dist/index.d.ts +8 -30
  21. package/dist/index.js +2 -2
  22. package/dist/network/index.cjs +681 -4
  23. package/dist/network/index.cjs.map +1 -1
  24. package/dist/network/index.d.cts +126 -5
  25. package/dist/network/index.d.ts +126 -5
  26. package/dist/network/index.js +680 -5
  27. package/dist/network/index.js.map +1 -1
  28. package/dist/systems/index.cjs +16 -8
  29. package/dist/systems/index.cjs.map +1 -1
  30. package/dist/systems/index.d.cts +2 -2
  31. package/dist/systems/index.d.ts +2 -2
  32. package/dist/systems/index.js +1 -1
  33. package/dist/types.d.cts +1 -1
  34. package/dist/types.d.ts +1 -1
  35. package/dist/webgpu/index.d.ts +2 -2
  36. package/dist/worldSnapshotUtils.d.cts +1 -1
  37. package/dist/worldSnapshotUtils.d.ts +1 -1
  38. package/package.json +1 -1
  39. package/dist/chunk-VYIWOXAY.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { y as NetworkTransport, z as NetEntityView, A as NetPose, B as EcsSystem, F as NetworkService, W as World, G as EntityId, H as NetworkHandle } from '../System-8D-XBDKZ.cjs';
2
- export { J as NetSpawnOptions } from '../System-8D-XBDKZ.cjs';
1
+ import { y as NetworkTransport, z as NetEntityView, A as NetPose, B as NetSound, F as VoiceFromRoom, G as VoiceToRoom, H as VoiceHandle, J as VoicePeer, K as EcsSystem, L as NetworkService, W as World, M as EntityId, O as NetworkHandle } from '../System-BldSHxZV.cjs';
2
+ export { Q as NetSpawnOptions, R as VoiceSignal } from '../System-BldSHxZV.cjs';
3
3
  import 'three';
4
4
  import '@dimforge/rapier3d-compat';
5
5
  import '../animation/index.cjs';
@@ -25,6 +25,8 @@ declare class ColyseusTransport implements NetworkTransport {
25
25
  onPlayerLeave(cb: (id: string) => void): void;
26
26
  onMessage(cb: (name: string, payload: unknown, from: string) => void): void;
27
27
  onCorrect(cb: (id: string, pose: NetPose) => void): void;
28
+ onSound(cb: (sound: NetSound, from: string) => void): void;
29
+ onVoice(cb: (message: VoiceFromRoom) => void): void;
28
30
  onClose(cb: () => void): void;
29
31
  registerScene(entities: Parameters<NetworkTransport["registerScene"]>[0]): void;
30
32
  spawn(request: Parameters<NetworkTransport["spawn"]>[0]): void;
@@ -32,6 +34,8 @@ declare class ColyseusTransport implements NetworkTransport {
32
34
  sendPose(id: string, pose: NetPose): void;
33
35
  setProp(id: string, key: string, json: string): void;
34
36
  send(name: string, payload: unknown): void;
37
+ sendSound(sound: NetSound): void;
38
+ sendVoice(message: VoiceToRoom): void;
35
39
  leave(): void;
36
40
  }
37
41
 
@@ -41,6 +45,110 @@ declare class ColyseusTransport implements NetworkTransport {
41
45
  */
42
46
  declare function withLatency(transport: NetworkTransport, ms: number): NetworkTransport;
43
47
 
48
+ interface VoiceMeter {
49
+ level(): number;
50
+ close(): void;
51
+ }
52
+ /** One person's voice coming out of the speakers. */
53
+ interface RemoteVoice {
54
+ setVolume(volume: number): void;
55
+ /** Where they are, or `null` to hear them everywhere. */
56
+ setPosition(position: {
57
+ x: number;
58
+ y: number;
59
+ z: number;
60
+ } | null): void;
61
+ stop(): void;
62
+ }
63
+ /** Everything voice needs from a browser, so the rest runs under test with fakes. */
64
+ interface VoiceDeps {
65
+ /** Whether this page can do voice at all: a mic needs https. */
66
+ supported(): boolean;
67
+ createConnection(config: RTCConfiguration): RTCPeerConnection;
68
+ getMic(constraints: MediaStreamConstraints): Promise<MediaStream>;
69
+ /** The mic is being taken or let go. iOS needs a different audio session while it's held. */
70
+ setCapture(on: boolean): void;
71
+ analyse(source: MediaStream | MediaStreamTrack): VoiceMeter | null;
72
+ playRemote(track: MediaStreamTrack): RemoteVoice;
73
+ /** Dip the music for this long. Called again while someone keeps talking. */
74
+ duck(seconds: number): void;
75
+ /** Where this player's character is, when they have one. */
76
+ positionOf(peerId: string): {
77
+ x: number;
78
+ y: number;
79
+ z: number;
80
+ } | null;
81
+ /** Run `fn` on a timer, and return how to stop it. */
82
+ every(ms: number, fn: () => void): () => void;
83
+ }
84
+ /**
85
+ * Voice chat between the players in a room: a direct connection to each other
86
+ * player, so the game server never carries audio, only the messages that set
87
+ * those connections up. Nothing is captured until the player turns it on, and
88
+ * only others who turned it on can hear them. Direct connections cost everyone
89
+ * upload per person, so rooms stop at the size the server says (8 by default).
90
+ */
91
+ declare class VoiceChat implements VoiceHandle {
92
+ private readonly transport;
93
+ private readonly deps;
94
+ available: boolean;
95
+ state: VoiceHandle["state"];
96
+ micMuted: boolean;
97
+ talking: boolean;
98
+ error: string;
99
+ /** Hear each voice from its character, when there is one. Off, everyone's in your ear. */
100
+ positional: boolean;
101
+ private readonly peersById;
102
+ private readonly listeners;
103
+ private config;
104
+ private track;
105
+ private meter;
106
+ private level;
107
+ private goodMs;
108
+ private stopTimers;
109
+ private disposed;
110
+ constructor(transport: Pick<NetworkTransport, "sendVoice" | "onVoice">, deps: VoiceDeps);
111
+ get peers(): VoicePeer[];
112
+ onChange(listener: () => void): () => void;
113
+ private changed;
114
+ /** Turn voice on. Call from a tap or key: that's what lets the browser ask for the mic. */
115
+ enable(): Promise<boolean>;
116
+ private acquire;
117
+ private release;
118
+ /** The mic stopped by itself: the phone took it for a call, or the device went away. */
119
+ private lost;
120
+ /** Turn voice off. The mic stops at once. */
121
+ disable(): void;
122
+ private shutDown;
123
+ /** Mute or unmute this player's mic. Everyone in voice sees it. */
124
+ setMicMuted(muted: boolean): Promise<void>;
125
+ /** Stop hearing someone. They aren't told. */
126
+ setPeerMuted(id: string, muted: boolean): void;
127
+ setPeerVolume(id: string, volume: number): void;
128
+ private fromRoom;
129
+ private addPeer;
130
+ private signal;
131
+ private hear;
132
+ private connectionChanged;
133
+ private call;
134
+ private offer;
135
+ private onSignal;
136
+ private sendMic;
137
+ private sendMicToAll;
138
+ private applyBitrate;
139
+ private setLevel;
140
+ /** Someone came or went: the rate each connection gets changes with it. */
141
+ private retune;
142
+ private closePeer;
143
+ private startTimers;
144
+ /** Who's talking, where they are, and the music under them. */
145
+ private poll;
146
+ /** Step quality to what the connections can carry. */
147
+ private tick;
148
+ /** The room is going: stop everything. There's no one left to tell. */
149
+ dispose(): void;
150
+ }
151
+
44
152
  /**
45
153
  * Keeps a world in step with a shared room: spawns what others spawned, sends
46
154
  * what this client owns, and plays back what it doesn't. Add it to
@@ -58,9 +166,16 @@ declare class NetworkSystem implements EcsSystem, NetworkService {
58
166
  private readonly listeners;
59
167
  private readonly handles;
60
168
  private spawnedAvatar;
169
+ /** Voice chat, once connected with it on. */
170
+ voice: VoiceChat | null;
61
171
  constructor(now?: () => number);
62
- /** Join the shared world. Call after hydrating, so scene objects exist. */
63
- connect(world: World, transport: NetworkTransport): void;
172
+ /**
173
+ * Join the shared world. Call after hydrating, so scene objects exist.
174
+ * `voice: true` adds voice chat; the room still decides whether it's offered.
175
+ */
176
+ connect(world: World, transport: NetworkTransport, options?: {
177
+ voice?: boolean | VoiceDeps;
178
+ }): void;
64
179
  /** Scene objects: every client hydrates the same scene, so their ids already match. */
65
180
  private registerScene;
66
181
  private spawnAvatar;
@@ -72,6 +187,9 @@ declare class NetworkSystem implements EcsSystem, NetworkService {
72
187
  private entityRemoved;
73
188
  private applyProps;
74
189
  private corrected;
190
+ private heardSound;
191
+ /** Where a player's character is: the first thing they spawned, which is their avatar. */
192
+ private positionOf;
75
193
  private disconnected;
76
194
  /** Call a Behaviour hook: on one entity's scripts, or every script. */
77
195
  private dispatch;
@@ -95,4 +213,7 @@ declare class SnapshotBuffer {
95
213
  sample(at: number): NetPose | null;
96
214
  }
97
215
 
98
- export { ColyseusTransport, NetEntityView, NetPose, NetworkHandle, NetworkService, NetworkSystem, NetworkTransport, SnapshotBuffer, withLatency };
216
+ /** Voice on a real page. */
217
+ declare function browserVoiceDeps(world: World, positionOf: VoiceDeps["positionOf"]): VoiceDeps;
218
+
219
+ export { ColyseusTransport, NetEntityView, NetPose, NetSound, NetworkHandle, NetworkService, NetworkSystem, NetworkTransport, SnapshotBuffer, VoiceChat, type VoiceDeps, VoiceFromRoom, VoiceHandle, VoicePeer, VoiceToRoom, browserVoiceDeps, withLatency };
@@ -1,5 +1,5 @@
1
- import { G as NetworkTransport, H as NetEntityView, J as NetPose, K as EcsSystem, L as NetworkService, W as World, M as EntityId, O as NetworkHandle } from '../System-DPMAW30g.js';
2
- export { Q as NetSpawnOptions } from '../System-DPMAW30g.js';
1
+ import { G as NetworkTransport, H as NetEntityView, J as NetPose, K as NetSound, L as VoiceFromRoom, M as VoiceToRoom, O as VoiceHandle, Q as VoicePeer, S as EcsSystem, U as NetworkService, W as World, X as EntityId, Y as NetworkHandle } from '../System-CADhPyQs.js';
2
+ export { Z as NetSpawnOptions, _ as VoiceSignal } from '../System-CADhPyQs.js';
3
3
  import 'three';
4
4
  import '@dimforge/rapier3d-compat';
5
5
  import '../animation/index.js';
@@ -25,6 +25,8 @@ declare class ColyseusTransport implements NetworkTransport {
25
25
  onPlayerLeave(cb: (id: string) => void): void;
26
26
  onMessage(cb: (name: string, payload: unknown, from: string) => void): void;
27
27
  onCorrect(cb: (id: string, pose: NetPose) => void): void;
28
+ onSound(cb: (sound: NetSound, from: string) => void): void;
29
+ onVoice(cb: (message: VoiceFromRoom) => void): void;
28
30
  onClose(cb: () => void): void;
29
31
  registerScene(entities: Parameters<NetworkTransport["registerScene"]>[0]): void;
30
32
  spawn(request: Parameters<NetworkTransport["spawn"]>[0]): void;
@@ -32,6 +34,8 @@ declare class ColyseusTransport implements NetworkTransport {
32
34
  sendPose(id: string, pose: NetPose): void;
33
35
  setProp(id: string, key: string, json: string): void;
34
36
  send(name: string, payload: unknown): void;
37
+ sendSound(sound: NetSound): void;
38
+ sendVoice(message: VoiceToRoom): void;
35
39
  leave(): void;
36
40
  }
37
41
 
@@ -41,6 +45,110 @@ declare class ColyseusTransport implements NetworkTransport {
41
45
  */
42
46
  declare function withLatency(transport: NetworkTransport, ms: number): NetworkTransport;
43
47
 
48
+ interface VoiceMeter {
49
+ level(): number;
50
+ close(): void;
51
+ }
52
+ /** One person's voice coming out of the speakers. */
53
+ interface RemoteVoice {
54
+ setVolume(volume: number): void;
55
+ /** Where they are, or `null` to hear them everywhere. */
56
+ setPosition(position: {
57
+ x: number;
58
+ y: number;
59
+ z: number;
60
+ } | null): void;
61
+ stop(): void;
62
+ }
63
+ /** Everything voice needs from a browser, so the rest runs under test with fakes. */
64
+ interface VoiceDeps {
65
+ /** Whether this page can do voice at all: a mic needs https. */
66
+ supported(): boolean;
67
+ createConnection(config: RTCConfiguration): RTCPeerConnection;
68
+ getMic(constraints: MediaStreamConstraints): Promise<MediaStream>;
69
+ /** The mic is being taken or let go. iOS needs a different audio session while it's held. */
70
+ setCapture(on: boolean): void;
71
+ analyse(source: MediaStream | MediaStreamTrack): VoiceMeter | null;
72
+ playRemote(track: MediaStreamTrack): RemoteVoice;
73
+ /** Dip the music for this long. Called again while someone keeps talking. */
74
+ duck(seconds: number): void;
75
+ /** Where this player's character is, when they have one. */
76
+ positionOf(peerId: string): {
77
+ x: number;
78
+ y: number;
79
+ z: number;
80
+ } | null;
81
+ /** Run `fn` on a timer, and return how to stop it. */
82
+ every(ms: number, fn: () => void): () => void;
83
+ }
84
+ /**
85
+ * Voice chat between the players in a room: a direct connection to each other
86
+ * player, so the game server never carries audio, only the messages that set
87
+ * those connections up. Nothing is captured until the player turns it on, and
88
+ * only others who turned it on can hear them. Direct connections cost everyone
89
+ * upload per person, so rooms stop at the size the server says (8 by default).
90
+ */
91
+ declare class VoiceChat implements VoiceHandle {
92
+ private readonly transport;
93
+ private readonly deps;
94
+ available: boolean;
95
+ state: VoiceHandle["state"];
96
+ micMuted: boolean;
97
+ talking: boolean;
98
+ error: string;
99
+ /** Hear each voice from its character, when there is one. Off, everyone's in your ear. */
100
+ positional: boolean;
101
+ private readonly peersById;
102
+ private readonly listeners;
103
+ private config;
104
+ private track;
105
+ private meter;
106
+ private level;
107
+ private goodMs;
108
+ private stopTimers;
109
+ private disposed;
110
+ constructor(transport: Pick<NetworkTransport, "sendVoice" | "onVoice">, deps: VoiceDeps);
111
+ get peers(): VoicePeer[];
112
+ onChange(listener: () => void): () => void;
113
+ private changed;
114
+ /** Turn voice on. Call from a tap or key: that's what lets the browser ask for the mic. */
115
+ enable(): Promise<boolean>;
116
+ private acquire;
117
+ private release;
118
+ /** The mic stopped by itself: the phone took it for a call, or the device went away. */
119
+ private lost;
120
+ /** Turn voice off. The mic stops at once. */
121
+ disable(): void;
122
+ private shutDown;
123
+ /** Mute or unmute this player's mic. Everyone in voice sees it. */
124
+ setMicMuted(muted: boolean): Promise<void>;
125
+ /** Stop hearing someone. They aren't told. */
126
+ setPeerMuted(id: string, muted: boolean): void;
127
+ setPeerVolume(id: string, volume: number): void;
128
+ private fromRoom;
129
+ private addPeer;
130
+ private signal;
131
+ private hear;
132
+ private connectionChanged;
133
+ private call;
134
+ private offer;
135
+ private onSignal;
136
+ private sendMic;
137
+ private sendMicToAll;
138
+ private applyBitrate;
139
+ private setLevel;
140
+ /** Someone came or went: the rate each connection gets changes with it. */
141
+ private retune;
142
+ private closePeer;
143
+ private startTimers;
144
+ /** Who's talking, where they are, and the music under them. */
145
+ private poll;
146
+ /** Step quality to what the connections can carry. */
147
+ private tick;
148
+ /** The room is going: stop everything. There's no one left to tell. */
149
+ dispose(): void;
150
+ }
151
+
44
152
  /**
45
153
  * Keeps a world in step with a shared room: spawns what others spawned, sends
46
154
  * what this client owns, and plays back what it doesn't. Add it to
@@ -58,9 +166,16 @@ declare class NetworkSystem implements EcsSystem, NetworkService {
58
166
  private readonly listeners;
59
167
  private readonly handles;
60
168
  private spawnedAvatar;
169
+ /** Voice chat, once connected with it on. */
170
+ voice: VoiceChat | null;
61
171
  constructor(now?: () => number);
62
- /** Join the shared world. Call after hydrating, so scene objects exist. */
63
- connect(world: World, transport: NetworkTransport): void;
172
+ /**
173
+ * Join the shared world. Call after hydrating, so scene objects exist.
174
+ * `voice: true` adds voice chat; the room still decides whether it's offered.
175
+ */
176
+ connect(world: World, transport: NetworkTransport, options?: {
177
+ voice?: boolean | VoiceDeps;
178
+ }): void;
64
179
  /** Scene objects: every client hydrates the same scene, so their ids already match. */
65
180
  private registerScene;
66
181
  private spawnAvatar;
@@ -72,6 +187,9 @@ declare class NetworkSystem implements EcsSystem, NetworkService {
72
187
  private entityRemoved;
73
188
  private applyProps;
74
189
  private corrected;
190
+ private heardSound;
191
+ /** Where a player's character is: the first thing they spawned, which is their avatar. */
192
+ private positionOf;
75
193
  private disconnected;
76
194
  /** Call a Behaviour hook: on one entity's scripts, or every script. */
77
195
  private dispatch;
@@ -95,4 +213,7 @@ declare class SnapshotBuffer {
95
213
  sample(at: number): NetPose | null;
96
214
  }
97
215
 
98
- export { ColyseusTransport, NetEntityView, NetPose, NetworkHandle, NetworkService, NetworkSystem, NetworkTransport, SnapshotBuffer, withLatency };
216
+ /** Voice on a real page. */
217
+ declare function browserVoiceDeps(world: World, positionOf: VoiceDeps["positionOf"]): VoiceDeps;
218
+
219
+ export { ColyseusTransport, NetEntityView, NetPose, NetSound, NetworkHandle, NetworkService, NetworkSystem, NetworkTransport, SnapshotBuffer, VoiceChat, type VoiceDeps, VoiceFromRoom, VoiceHandle, VoicePeer, VoiceToRoom, browserVoiceDeps, withLatency };