@worldmesh/runtime 0.2.1 → 0.2.3

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 (115) hide show
  1. package/README.md +48 -8
  2. package/dist/audio/footsteps.d.ts +37 -0
  3. package/dist/audio/footsteps.d.ts.map +1 -0
  4. package/dist/audio/footsteps.js +178 -0
  5. package/dist/audio/footsteps.js.map +1 -0
  6. package/dist/avatar/descriptor.d.ts +15 -0
  7. package/dist/avatar/descriptor.d.ts.map +1 -1
  8. package/dist/avatar/descriptor.js +19 -0
  9. package/dist/avatar/descriptor.js.map +1 -1
  10. package/dist/avatar/loader.d.ts +12 -1
  11. package/dist/avatar/loader.d.ts.map +1 -1
  12. package/dist/avatar/loader.js +16 -1
  13. package/dist/avatar/loader.js.map +1 -1
  14. package/dist/avatar/share.d.ts +30 -0
  15. package/dist/avatar/share.d.ts.map +1 -0
  16. package/dist/avatar/share.js +203 -0
  17. package/dist/avatar/share.js.map +1 -0
  18. package/dist/camera/cameraRig.d.ts +4 -0
  19. package/dist/camera/cameraRig.d.ts.map +1 -1
  20. package/dist/camera/cameraRig.js +10 -1
  21. package/dist/camera/cameraRig.js.map +1 -1
  22. package/dist/camera/viewHandoff.d.ts +20 -0
  23. package/dist/camera/viewHandoff.d.ts.map +1 -0
  24. package/dist/camera/viewHandoff.js +64 -0
  25. package/dist/camera/viewHandoff.js.map +1 -0
  26. package/dist/controls/input.d.ts +29 -0
  27. package/dist/controls/input.d.ts.map +1 -1
  28. package/dist/controls/input.js +124 -1
  29. package/dist/controls/input.js.map +1 -1
  30. package/dist/controls/touch.d.ts +10 -0
  31. package/dist/controls/touch.d.ts.map +1 -1
  32. package/dist/controls/touch.js +57 -1
  33. package/dist/controls/touch.js.map +1 -1
  34. package/dist/core/worldmesh.d.ts +9 -0
  35. package/dist/core/worldmesh.d.ts.map +1 -1
  36. package/dist/core/worldmesh.js +498 -26
  37. package/dist/core/worldmesh.js.map +1 -1
  38. package/dist/hosted.d.ts +3 -0
  39. package/dist/hosted.d.ts.map +1 -0
  40. package/dist/hosted.js +5 -0
  41. package/dist/hosted.js.map +1 -0
  42. package/dist/index.d.ts +16 -9
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +12 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/load.d.ts +23 -0
  47. package/dist/load.d.ts.map +1 -0
  48. package/dist/load.js +83 -0
  49. package/dist/load.js.map +1 -0
  50. package/dist/net/follow.d.ts +7 -0
  51. package/dist/net/follow.d.ts.map +1 -0
  52. package/dist/net/follow.js +10 -0
  53. package/dist/net/follow.js.map +1 -0
  54. package/dist/net/presence.d.ts +125 -3
  55. package/dist/net/presence.d.ts.map +1 -1
  56. package/dist/net/presence.js +471 -24
  57. package/dist/net/presence.js.map +1 -1
  58. package/dist/net/roomFull.d.ts +44 -0
  59. package/dist/net/roomFull.d.ts.map +1 -0
  60. package/dist/net/roomFull.js +147 -0
  61. package/dist/net/roomFull.js.map +1 -0
  62. package/dist/player/avatar.d.ts +17 -4
  63. package/dist/player/avatar.d.ts.map +1 -1
  64. package/dist/player/avatar.js +85 -18
  65. package/dist/player/avatar.js.map +1 -1
  66. package/dist/player/player.d.ts +6 -2
  67. package/dist/player/player.d.ts.map +1 -1
  68. package/dist/player/player.js +13 -3
  69. package/dist/player/player.js.map +1 -1
  70. package/dist/player/stroke.d.ts +11 -0
  71. package/dist/player/stroke.d.ts.map +1 -0
  72. package/dist/player/stroke.js +96 -0
  73. package/dist/player/stroke.js.map +1 -0
  74. package/dist/portals/portals.d.ts +1 -1
  75. package/dist/portals/portals.d.ts.map +1 -1
  76. package/dist/portals/portals.js +6 -2
  77. package/dist/portals/portals.js.map +1 -1
  78. package/dist/types.d.ts +53 -9
  79. package/dist/types.d.ts.map +1 -1
  80. package/dist/ui/overlay.d.ts +18 -0
  81. package/dist/ui/overlay.d.ts.map +1 -1
  82. package/dist/ui/overlay.js +166 -1
  83. package/dist/ui/overlay.js.map +1 -1
  84. package/dist/version.d.ts +4 -0
  85. package/dist/version.d.ts.map +1 -0
  86. package/dist/version.js +4 -0
  87. package/dist/version.js.map +1 -0
  88. package/dist/xr/session.d.ts +13 -0
  89. package/dist/xr/session.d.ts.map +1 -0
  90. package/dist/xr/session.js +33 -0
  91. package/dist/xr/session.js.map +1 -0
  92. package/package.json +1 -1
  93. package/src/audio/footsteps.ts +185 -0
  94. package/src/avatar/descriptor.ts +28 -0
  95. package/src/avatar/loader.ts +19 -2
  96. package/src/avatar/share.ts +196 -0
  97. package/src/camera/cameraRig.ts +10 -1
  98. package/src/camera/viewHandoff.ts +67 -0
  99. package/src/controls/input.ts +119 -1
  100. package/src/controls/touch.ts +59 -1
  101. package/src/core/worldmesh.ts +495 -25
  102. package/src/hosted.ts +4 -0
  103. package/src/index.ts +16 -9
  104. package/src/load.ts +103 -0
  105. package/src/net/follow.ts +9 -0
  106. package/src/net/presence.ts +547 -27
  107. package/src/net/roomFull.ts +160 -0
  108. package/src/player/avatar.ts +87 -18
  109. package/src/player/player.ts +13 -4
  110. package/src/player/stroke.ts +93 -0
  111. package/src/portals/portals.ts +5 -2
  112. package/src/types.ts +52 -9
  113. package/src/ui/overlay.ts +171 -1
  114. package/src/version.ts +3 -0
  115. package/src/xr/session.ts +33 -0
@@ -98,6 +98,49 @@ const CSS = `
98
98
  border-color: rgba(255,255,255,0.6);
99
99
  transform: scale(1.02);
100
100
  }
101
+ .wm-vr-launch {
102
+ position: absolute;
103
+ top: max(16px, env(safe-area-inset-top));
104
+ left: 50%;
105
+ transform: translateX(-50%);
106
+ pointer-events: auto;
107
+ font-size: 13px;
108
+ letter-spacing: .06em;
109
+ text-transform: uppercase;
110
+ padding: 10px 22px;
111
+ border: 1px solid rgba(255,255,255,0.4);
112
+ border-radius: 999px;
113
+ background: rgba(8,11,16,0.72);
114
+ color: #fff;
115
+ cursor: pointer;
116
+ font-family: inherit;
117
+ font-weight: 600;
118
+ touch-action: manipulation;
119
+ -webkit-tap-highlight-color: transparent;
120
+ }
121
+ .wm-vr-launch:hover, .wm-vr-launch:active {
122
+ background: rgba(8,11,16,0.9);
123
+ border-color: rgba(255,255,255,0.7);
124
+ }
125
+ .wm-overlay:not([data-locked="true"]) .wm-vr-launch,
126
+ .wm-overlay[data-xr="true"] .wm-vr-launch,
127
+ .wm-overlay[data-xr="true"] .wm-vr-menu {
128
+ display: none;
129
+ }
130
+ .wm-vr-menu {
131
+ font-size: 13px;
132
+ letter-spacing: .06em;
133
+ text-transform: uppercase;
134
+ padding: 10px 22px;
135
+ border: 1px solid rgba(255,255,255,0.35);
136
+ border-radius: 999px;
137
+ background: rgba(255,255,255,0.08);
138
+ color: #fff;
139
+ cursor: pointer;
140
+ font-family: inherit;
141
+ font-weight: 500;
142
+ touch-action: manipulation;
143
+ }
101
144
  .wm-keys {
102
145
  display: grid;
103
146
  grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -198,6 +241,55 @@ const CSS = `
198
241
  transition: opacity .2s ease;
199
242
  }
200
243
  .wm-overlay[data-locked="true"] .wm-hint { opacity: 1; }
244
+ .wm-room-full {
245
+ position: absolute;
246
+ inset: 0;
247
+ display: none;
248
+ flex-direction: column;
249
+ align-items: center;
250
+ justify-content: center;
251
+ gap: 18px;
252
+ background: rgba(8, 11, 16, 0.22);
253
+ backdrop-filter: blur(8px);
254
+ -webkit-backdrop-filter: blur(8px);
255
+ pointer-events: auto;
256
+ z-index: 6;
257
+ padding: max(20px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
258
+ }
259
+ .wm-overlay[data-room-full="true"] .wm-room-full { display: flex; }
260
+ .wm-overlay[data-room-full="true"] .wm-lock { display: none; }
261
+ .wm-room-full-label {
262
+ margin: 0;
263
+ padding: 14px 36px;
264
+ border-radius: 4px;
265
+ background: rgba(160, 12, 18, 0.92);
266
+ color: #fff;
267
+ font-family: Urbanist, ui-sans-serif, system-ui, sans-serif;
268
+ font-size: clamp(22px, 4.4vw, 36px);
269
+ font-weight: 700;
270
+ letter-spacing: .02em;
271
+ text-align: center;
272
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
273
+ }
274
+ .wm-room-full-retry {
275
+ font-size: 13.5px;
276
+ letter-spacing: .14em;
277
+ text-transform: uppercase;
278
+ padding: 12px 28px;
279
+ border: 1px solid rgba(255,255,255,0.45);
280
+ border-radius: 999px;
281
+ background: rgba(255,255,255,0.12);
282
+ color: #fff;
283
+ cursor: pointer;
284
+ font-family: inherit;
285
+ font-weight: 500;
286
+ touch-action: manipulation;
287
+ -webkit-tap-highlight-color: transparent;
288
+ }
289
+ .wm-room-full-retry:hover, .wm-room-full-retry:active {
290
+ background: rgba(255,255,255,0.22);
291
+ border-color: rgba(255,255,255,0.7);
292
+ }
201
293
 
202
294
  @media (max-width: 400px) {
203
295
  .wm-lock {
@@ -273,7 +365,13 @@ export class Overlay {
273
365
  root;
274
366
  prompt;
275
367
  lock;
368
+ vrLaunch;
369
+ vrMenu;
370
+ roomFull;
371
+ roomFullLabel;
372
+ roomFullRetry;
276
373
  onEnter;
374
+ onRoomFullRetry = null;
277
375
  deferLockPanel;
278
376
  constructor(options) {
279
377
  injectStyles();
@@ -286,7 +384,7 @@ export class Overlay {
286
384
  this.root.dataset.locked = options.moveBeforeLock ? 'true' : 'false';
287
385
  if (this.deferLockPanel)
288
386
  this.root.dataset.deferLock = 'true';
289
- if (options.crosshair !== false) {
387
+ if (options.crosshair === true) {
290
388
  const crosshair = document.createElement('div');
291
389
  crosshair.className = 'wm-crosshair';
292
390
  this.root.appendChild(crosshair);
@@ -325,6 +423,17 @@ export class Overlay {
325
423
  }
326
424
  handleEnter(event);
327
425
  });
426
+ const vrMenu = document.createElement('button');
427
+ vrMenu.type = 'button';
428
+ vrMenu.className = 'wm-vr-menu';
429
+ vrMenu.textContent = 'Enter VR';
430
+ vrMenu.hidden = true;
431
+ vrMenu.addEventListener('click', (event) => {
432
+ event.stopPropagation();
433
+ options.onEnterVr?.();
434
+ });
435
+ this.vrMenu = vrMenu;
436
+ content.appendChild(vrMenu);
328
437
  if (options.controlsHint !== false) {
329
438
  const keys = document.createElement('div');
330
439
  keys.className = 'wm-keys';
@@ -361,6 +470,9 @@ export class Overlay {
361
470
  const badge = document.createElement('a');
362
471
  badge.className = 'wm-badge';
363
472
  badge.href = options.hubUrl ?? 'https://worldmesh.net';
473
+ // Shown inside a hub's door: back to the hub replaces the whole page, not the frame.
474
+ if (window.parent !== window)
475
+ badge.target = '_top';
364
476
  const dot = document.createElement('span');
365
477
  dot.className = 'wm-badge-dot';
366
478
  const label = document.createElement('span');
@@ -372,8 +484,49 @@ export class Overlay {
372
484
  hint.className = 'wm-hint';
373
485
  hint.textContent = isTouch ? 'Tap ⏸ to open the menu' : 'Esc to open the menu';
374
486
  this.root.appendChild(hint);
487
+ const vrLaunch = document.createElement('button');
488
+ vrLaunch.type = 'button';
489
+ vrLaunch.className = 'wm-vr-launch';
490
+ vrLaunch.textContent = 'Enter VR';
491
+ vrLaunch.hidden = true;
492
+ vrLaunch.addEventListener('click', (event) => {
493
+ event.stopPropagation();
494
+ options.onEnterVr?.();
495
+ });
496
+ this.vrLaunch = vrLaunch;
497
+ this.root.appendChild(vrLaunch);
498
+ const roomFull = document.createElement('div');
499
+ roomFull.className = 'wm-room-full';
500
+ roomFull.hidden = true;
501
+ const roomFullLabel = document.createElement('p');
502
+ roomFullLabel.className = 'wm-room-full-label';
503
+ const roomFullRetry = document.createElement('button');
504
+ roomFullRetry.type = 'button';
505
+ roomFullRetry.className = 'wm-room-full-retry';
506
+ roomFullRetry.textContent = 'Try again';
507
+ roomFullRetry.hidden = true;
508
+ roomFullRetry.addEventListener('click', (event) => {
509
+ event.stopPropagation();
510
+ this.onRoomFullRetry?.();
511
+ });
512
+ roomFull.append(roomFullLabel, roomFullRetry);
513
+ this.roomFull = roomFull;
514
+ this.roomFullLabel = roomFullLabel;
515
+ this.roomFullRetry = roomFullRetry;
516
+ this.root.appendChild(roomFull);
375
517
  document.body.appendChild(this.root);
376
518
  }
519
+ /** Show Enter VR once the browser reports immersive-vr support. */
520
+ setVrAvailable(available) {
521
+ this.vrLaunch.hidden = !available;
522
+ this.vrMenu.hidden = !available;
523
+ }
524
+ /** Hide the 2D Enter VR controls while the headset is presenting. */
525
+ setVrPresenting(presenting) {
526
+ this.root.dataset.xr = String(presenting);
527
+ if (presenting)
528
+ this.setLocked(true);
529
+ }
377
530
  /** The pause screen, with the control list, is on screen. */
378
531
  isPaused() {
379
532
  return this.root.dataset.lockReady === 'true' && this.root.dataset.locked !== 'true';
@@ -402,6 +555,18 @@ export class Overlay {
402
555
  if (content instanceof HTMLElement)
403
556
  content.style.visibility = '';
404
557
  }
558
+ /**
559
+ * Presence refused the join because the room is full. Soft-blur the scene
560
+ * and show the same red banner language as a full world door.
561
+ */
562
+ setRoomFull(label, options) {
563
+ const full = Boolean(label);
564
+ this.root.dataset.roomFull = String(full);
565
+ this.roomFull.hidden = !full;
566
+ this.roomFullLabel.textContent = label ?? '';
567
+ this.onRoomFullRetry = options?.onRetry ?? null;
568
+ this.roomFullRetry.hidden = !this.onRoomFullRetry;
569
+ }
405
570
  setPrompt(text) {
406
571
  if (!text) {
407
572
  this.prompt.dataset.visible = 'false';
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/ui/overlay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/ui/overlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const WORLDMESH_VERSION = "0.2.3";
2
+ /** Bumped when the world-facing contract changes in an incompatible way. */
3
+ export declare const WORLDMESH_PROTOCOL = 1;
4
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,UAAU,CAAC;AACzC,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,IAAI,CAAC"}
@@ -0,0 +1,4 @@
1
+ export const WORLDMESH_VERSION = '0.2.3';
2
+ /** Bumped when the world-facing contract changes in an incompatible way. */
3
+ export const WORLDMESH_PROTOCOL = 1;
4
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AACzC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { WebGLRenderer } from 'three';
2
+ export declare const IMMERSIVE_VR = "immersive-vr";
3
+ /**
4
+ * Whether this browser can start a WebXR immersive-vr session.
5
+ * Headset browsers resolve true; ordinary desktop Chrome resolves false.
6
+ */
7
+ export declare function immersiveVrSupported(): Promise<boolean>;
8
+ /**
9
+ * Ask the browser for an immersive VR session and hand it to Three.js.
10
+ * Must run from a user gesture (the Enter VR button).
11
+ */
12
+ export declare function requestImmersiveVr(renderer: WebGLRenderer): Promise<XRSession>;
13
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/xr/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQ7D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAUpF"}
@@ -0,0 +1,33 @@
1
+ export const IMMERSIVE_VR = 'immersive-vr';
2
+ /**
3
+ * Whether this browser can start a WebXR immersive-vr session.
4
+ * Headset browsers resolve true; ordinary desktop Chrome resolves false.
5
+ */
6
+ export async function immersiveVrSupported() {
7
+ const xr = navigator.xr;
8
+ if (!xr?.isSessionSupported)
9
+ return false;
10
+ try {
11
+ return await xr.isSessionSupported(IMMERSIVE_VR);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /**
18
+ * Ask the browser for an immersive VR session and hand it to Three.js.
19
+ * Must run from a user gesture (the Enter VR button).
20
+ */
21
+ export async function requestImmersiveVr(renderer) {
22
+ const xr = navigator.xr;
23
+ if (!xr?.requestSession)
24
+ throw new Error('WebXR is not available');
25
+ renderer.xr.enabled = true;
26
+ renderer.xr.setReferenceSpaceType('local-floor');
27
+ const session = await xr.requestSession(IMMERSIVE_VR, {
28
+ optionalFeatures: ['local-floor', 'bounded-floor'],
29
+ });
30
+ await renderer.xr.setSession(session);
31
+ return session;
32
+ }
33
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/xr/session.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,EAAE,kBAAkB;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAuB;IAC9D,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,EAAE,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACnE,QAAQ,CAAC,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC,YAAY,EAAE;QACpD,gBAAgB,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC;KACnD,CAAC,CAAC;IACH,MAAM,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worldmesh/runtime",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "The shared WorldMesh navigation runtime: controls, movement, camera, player, abilities and portals.",
5
5
  "keywords": [
6
6
  "worldmesh",
@@ -0,0 +1,185 @@
1
+ /** Metres walked between two footsteps. */
2
+ const STRIDE = 1.6;
3
+ /** Below this ground speed (m/s) the player is standing, not walking. */
4
+ const MIN_SPEED = 0.6;
5
+
6
+ /**
7
+ * Footstep sounds for the local player, synthesised with Web Audio so no
8
+ * world has to ship a sound file. Steps follow distance walked, so sprinting
9
+ * quickens them and crouching slows them without any extra tuning.
10
+ */
11
+ /** One audio context and noise buffer for every walker: browsers allow only a few contexts per page. */
12
+ let shared: { context: AudioContext; noise: AudioBuffer } | null = null;
13
+
14
+ export class Footsteps {
15
+ /**
16
+ * How loud this walker is where the listener stands: 1 for the player's own
17
+ * feet, less for someone further off, 0 for out of earshot.
18
+ */
19
+ loudness = 1;
20
+ private walked = 0;
21
+ private left = false;
22
+ private wasGrounded = true;
23
+ private lastVertical = 0;
24
+ /** Fastest fall since leaving the ground, so landings sound as hard as they were. */
25
+ private fallSpeed = 0;
26
+
27
+ /**
28
+ * Call once per frame with the horizontal speed and whether feet are on the
29
+ * ground. `footfall` says whether the avatar's foot landed this frame; when
30
+ * the avatar's animation cannot tell (null), steps fall back to distance.
31
+ */
32
+ update(
33
+ dt: number,
34
+ speed: number,
35
+ grounded: boolean,
36
+ footfall: boolean | null = null,
37
+ vertical = 0,
38
+ flying = false,
39
+ ): void {
40
+ if (!flying) this.updateAir(grounded, vertical);
41
+ this.wasGrounded = grounded;
42
+ this.lastVertical = vertical;
43
+ if (footfall !== null) {
44
+ if (footfall && grounded && speed >= MIN_SPEED) this.play(Math.min(1, speed / 9));
45
+ return;
46
+ }
47
+ if (!grounded || speed < MIN_SPEED) {
48
+ // Start the next walk half a stride in, so the first step comes quickly.
49
+ this.walked = STRIDE * 0.5;
50
+ return;
51
+ }
52
+ this.walked += speed * dt;
53
+ if (this.walked < STRIDE) return;
54
+ this.walked -= STRIDE * (0.92 + Math.random() * 0.16);
55
+ this.play(Math.min(1, speed / 9));
56
+ }
57
+
58
+ /** Jumps, double jumps and landings. */
59
+ private updateAir(grounded: boolean, vertical: number): void {
60
+ if (grounded) {
61
+ if (!this.wasGrounded && this.fallSpeed > 2) this.land(Math.min(1, this.fallSpeed / 20));
62
+ this.fallSpeed = 0;
63
+ return;
64
+ }
65
+ this.fallSpeed = Math.max(this.fallSpeed, -vertical);
66
+ const jumped = this.wasGrounded ? vertical > 1 : vertical - this.lastVertical > 3;
67
+ if (jumped) {
68
+ this.jump();
69
+ this.fallSpeed = 0;
70
+ }
71
+ }
72
+
73
+ /** Pushing off: a quick scuff, then a soft rush of air. Every part varies, like the steps. */
74
+ private jump(): void {
75
+ const jitter = (spread: number) => 1 + (Math.random() * 2 - 1) * spread;
76
+ this.play(0.6, { volume: 0.9 * jitter(0.3), decay: 0.7 * jitter(0.3), tone: 1.3 * jitter(0.2) });
77
+ const audio = this.audio();
78
+ if (!audio) return;
79
+ const { context, noise } = audio;
80
+ const now = context.currentTime + Math.random() * 0.02;
81
+ const length = 0.26 * jitter(0.3);
82
+ const source = context.createBufferSource();
83
+ source.buffer = noise;
84
+ source.playbackRate.value = jitter(0.2);
85
+ const filter = context.createBiquadFilter();
86
+ filter.type = 'bandpass';
87
+ filter.Q.value = 0.8 * jitter(0.4);
88
+ filter.frequency.setValueAtTime(500 * jitter(0.25), now);
89
+ filter.frequency.exponentialRampToValueAtTime(1400 * jitter(0.3), now + length * 0.85);
90
+ const gain = context.createGain();
91
+ gain.gain.setValueAtTime(0.0001, now);
92
+ gain.gain.exponentialRampToValueAtTime(0.034 * jitter(0.35) * this.loudness, now + 0.06 * jitter(0.4));
93
+ gain.gain.exponentialRampToValueAtTime(0.0001, now + length);
94
+ source.connect(filter).connect(gain).connect(context.destination);
95
+ source.start(now, Math.random() * (noise.duration - length - 0.05));
96
+ source.stop(now + length + 0.02);
97
+ }
98
+
99
+ /**
100
+ * Both feet coming down, heavier and longer the harder the fall. Usually one
101
+ * lands a moment before the other, by a different amount each time.
102
+ */
103
+ private land(hardness: number): void {
104
+ const jitter = (spread: number) => 1 + (Math.random() * 2 - 1) * spread;
105
+ const shape = () => ({
106
+ volume: (1.4 + hardness) * jitter(0.25),
107
+ decay: (1.4 + hardness * 0.6) * jitter(0.25),
108
+ tone: 0.8 * jitter(0.2),
109
+ });
110
+ this.play(0.4 + hardness * 0.6, shape());
111
+ if (Math.random() < 0.7) {
112
+ const second = shape();
113
+ second.volume *= 0.6;
114
+ window.setTimeout(() => this.play(0.4 + hardness * 0.6, second), 15 + Math.random() * 45);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * A soft scuff with a faint low thump: a step on firm ground. Every part is
120
+ * jittered, and left and right feet differ slightly, so no two sound alike.
121
+ */
122
+ private play(intensity: number, shape: { volume?: number; decay?: number; tone?: number } = {}): void {
123
+ const { volume: loudness = 1, decay: length = 1, tone = 1 } = shape;
124
+ const audio = this.audio();
125
+ if (!audio) return;
126
+ const { context, noise } = audio;
127
+ const jitter = (spread: number) => 1 + (Math.random() * 2 - 1) * spread;
128
+ this.left = !this.left;
129
+ const now = context.currentTime + Math.random() * 0.025;
130
+ const volume = (0.065 + intensity * 0.065) * jitter(0.3) * (this.left ? 1 : 0.85) * loudness * this.loudness;
131
+ const decay = 0.09 * jitter(0.35) * length;
132
+
133
+ const source = context.createBufferSource();
134
+ source.buffer = noise;
135
+ source.playbackRate.value = jitter(0.25);
136
+ const filter = context.createBiquadFilter();
137
+ filter.type = 'lowpass';
138
+ filter.frequency.value = (this.left ? 520 : 440) * jitter(0.3) * tone;
139
+ filter.Q.value = 0.4 + Math.random() * 0.6;
140
+ const gain = context.createGain();
141
+ // A few milliseconds of attack takes the click off the start.
142
+ gain.gain.setValueAtTime(0.0001, now);
143
+ gain.gain.exponentialRampToValueAtTime(volume, now + 0.008 * jitter(0.5));
144
+ gain.gain.exponentialRampToValueAtTime(0.0001, now + decay);
145
+ // Random offset into the noise, so each step starts on different grain.
146
+ const offset = Math.random() * (noise.duration - decay - 0.02);
147
+ source.connect(filter).connect(gain).connect(context.destination);
148
+ source.start(now, Math.max(0, offset));
149
+ source.stop(now + decay + 0.02);
150
+
151
+ const thump = context.createOscillator();
152
+ const pitch = 85 * jitter(0.2) * Math.min(1, tone);
153
+ thump.frequency.setValueAtTime(pitch, now);
154
+ thump.frequency.exponentialRampToValueAtTime(pitch * 0.5, now + 0.07 * length);
155
+ const thumpGain = context.createGain();
156
+ thumpGain.gain.setValueAtTime(0.0001, now);
157
+ thumpGain.gain.exponentialRampToValueAtTime(volume * 0.5 * jitter(0.4), now + 0.01);
158
+ thumpGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.08 * length);
159
+ thump.connect(thumpGain).connect(context.destination);
160
+ thump.start(now);
161
+ thump.stop(now + 0.09 * length + 0.01);
162
+ }
163
+
164
+ /** The shared audio, or null when there is none, it is not running yet, or this walker is out of earshot. */
165
+ private audio(): { context: AudioContext; noise: AudioBuffer } | null {
166
+ if (this.loudness < 0.02) return null;
167
+ if (!shared) {
168
+ if (typeof AudioContext === 'undefined') return null;
169
+ const context = new AudioContext();
170
+ const length = Math.floor(context.sampleRate * 0.6);
171
+ const noise = context.createBuffer(1, length, context.sampleRate);
172
+ const data = noise.getChannelData(0);
173
+ for (let i = 0; i < length; i++) data[i] = Math.random() * 2 - 1;
174
+ shared = { context, noise };
175
+ }
176
+ // Browsers start audio suspended until the page has had a click or key press.
177
+ if (shared.context.state === 'suspended') void shared.context.resume().catch(() => undefined);
178
+ return shared.context.state === 'running' ? shared : null;
179
+ }
180
+
181
+ dispose(): void {
182
+ // The shared context stays for the other walkers; nothing of this one's is left playing.
183
+ this.loudness = 0;
184
+ }
185
+ }
@@ -21,6 +21,32 @@ export interface AvatarDescriptor {
21
21
  expiresAt: string | null;
22
22
  /** The avatar's public page, for credit where its license asks for it. */
23
23
  sourceUrl: string | null;
24
+ /**
25
+ * The model link signed by the WorldMesh hub for showing to other players,
26
+ * or null when it may not be shown to them (see avatar/share.ts).
27
+ */
28
+ share?: SignedAvatarShare | null;
29
+ }
30
+
31
+ /** A model link the hub vouched for: `u` link, `f` format, `i` stable id, `x` expiry (unix seconds), `s` Ed25519 signature. */
32
+ export interface SignedAvatarShare {
33
+ u: string;
34
+ f: AvatarFormat;
35
+ i: string;
36
+ x: number;
37
+ s: string;
38
+ }
39
+
40
+ /** Accepts a signed share from the network only if it has the right shape. Says nothing about the signature. */
41
+ export function parseAvatarShare(value: unknown): SignedAvatarShare | null {
42
+ if (!value || typeof value !== 'object') return null;
43
+ const v = value as Record<string, unknown>;
44
+ if (typeof v.u !== 'string' || !v.u.startsWith('https:') || v.u.length > 1800 || !isLoadableUrl(v.u)) return null;
45
+ if (typeof v.f !== 'string' || !FORMATS.includes(v.f)) return null;
46
+ if (typeof v.i !== 'string' || !/^[a-z0-9]{1,16}$/.test(v.i)) return null;
47
+ if (typeof v.x !== 'number' || !Number.isInteger(v.x) || v.x <= 0 || v.x > 1e11) return null;
48
+ if (typeof v.s !== 'string' || !/^[A-Za-z0-9_-]{86}$/.test(v.s)) return null;
49
+ return { u: v.u, f: v.f as AvatarFormat, i: v.i, x: v.x, s: v.s };
24
50
  }
25
51
 
26
52
  const FORMATS: readonly string[] = ['vrm', 'glb', 'gltf'];
@@ -52,5 +78,7 @@ export function parseAvatarDescriptor(value: unknown): AvatarDescriptor | null {
52
78
  modelUrl: d.modelUrl,
53
79
  expiresAt: text(d.expiresAt),
54
80
  sourceUrl: isLoadableUrl(d.sourceUrl) ? d.sourceUrl : null,
81
+ // Absent (an older hub) is not the same as null (the hub says: do not show to others).
82
+ share: 'share' in d ? parseAvatarShare(d.share) : undefined,
55
83
  };
56
84
  }
@@ -1,5 +1,5 @@
1
1
  import { AnimationMixer, Box3, Group, MathUtils, Mesh, Texture, type AnimationAction, type Object3D } from 'three';
2
- import type { AvatarMotion } from '../player/avatar.js';
2
+ import { attachAvatarAppear, type AvatarMotion } from '../player/avatar.js';
3
3
  import type { AvatarDescriptor } from './descriptor.js';
4
4
 
5
5
  /** A loaded external avatar, normalised to the WorldMesh body convention. */
@@ -17,6 +17,19 @@ export interface LoadAvatarOptions {
17
17
  /** Refuse models larger than this. Defaults to 40 MB. */
18
18
  maxBytes?: number;
19
19
  signal?: AbortSignal;
20
+ /** The model file, already downloaded (downloadAvatarModel): nothing is fetched again. */
21
+ data?: ArrayBuffer;
22
+ }
23
+
24
+ const DEFAULT_MAX_BYTES = 40 * 1024 * 1024;
25
+
26
+ /**
27
+ * Just the download: the model file the descriptor points at, within the size
28
+ * limit. Lets a page fetch it once and hand the same bytes to loadAvatarModel
29
+ * and on to an embedded world.
30
+ */
31
+ export function downloadAvatarModel(descriptor: AvatarDescriptor, options: { maxBytes?: number; signal?: AbortSignal } = {}): Promise<ArrayBuffer> {
32
+ return download(descriptor.modelUrl, options.maxBytes ?? DEFAULT_MAX_BYTES, options.signal);
20
33
  }
21
34
 
22
35
  /**
@@ -26,7 +39,9 @@ export interface LoadAvatarOptions {
26
39
  * never download them.
27
40
  */
28
41
  export async function loadAvatarModel(descriptor: AvatarDescriptor, options: LoadAvatarOptions): Promise<LoadedAvatar> {
29
- const buffer = await download(descriptor.modelUrl, options.maxBytes ?? 40 * 1024 * 1024, options.signal);
42
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
43
+ if (options.data && options.data.byteLength > maxBytes) throw new Error('Model is too large');
44
+ const buffer = options.data ?? (await download(descriptor.modelUrl, maxBytes, options.signal));
30
45
  const [{ GLTFLoader }, vrmModule] = await Promise.all([
31
46
  import('three/examples/jsm/loaders/GLTFLoader.js'),
32
47
  descriptor.format === 'vrm' ? import('@pixiv/three-vrm') : Promise.resolve(null),
@@ -49,6 +64,8 @@ export async function loadAvatarModel(descriptor: AvatarDescriptor, options: Loa
49
64
  child.frustumCulled = false;
50
65
  if ((child as Mesh).isMesh) child.castShadow = true;
51
66
  });
67
+ // Warps in like the default body when a page brings it in (setAvatarAppear).
68
+ attachAvatarAppear(model);
52
69
 
53
70
  // glTF and VRM face +Z; WorldMesh bodies face -Z. Scale to the player and
54
71
  // stand the feet on y = 0.