@worldmesh/runtime 0.1.0 → 0.2.1

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 (72) hide show
  1. package/README.md +21 -2
  2. package/dist/avatar/descriptor.d.ts +27 -0
  3. package/dist/avatar/descriptor.d.ts.map +1 -0
  4. package/dist/avatar/descriptor.js +41 -0
  5. package/dist/avatar/descriptor.js.map +1 -0
  6. package/dist/avatar/handoff.d.ts +29 -0
  7. package/dist/avatar/handoff.d.ts.map +1 -0
  8. package/dist/avatar/handoff.js +92 -0
  9. package/dist/avatar/handoff.js.map +1 -0
  10. package/dist/avatar/loader.d.ts +26 -0
  11. package/dist/avatar/loader.d.ts.map +1 -0
  12. package/dist/avatar/loader.js +177 -0
  13. package/dist/avatar/loader.js.map +1 -0
  14. package/dist/controls/input.d.ts +25 -0
  15. package/dist/controls/input.d.ts.map +1 -1
  16. package/dist/controls/input.js +60 -2
  17. package/dist/controls/input.js.map +1 -1
  18. package/dist/controls/touch.d.ts.map +1 -1
  19. package/dist/controls/touch.js +5 -0
  20. package/dist/controls/touch.js.map +1 -1
  21. package/dist/core/worldmesh.d.ts.map +1 -1
  22. package/dist/core/worldmesh.js +114 -8
  23. package/dist/core/worldmesh.js.map +1 -1
  24. package/dist/index.d.ts +10 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +6 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/movement/controller.d.ts +10 -1
  29. package/dist/movement/controller.d.ts.map +1 -1
  30. package/dist/movement/controller.js +61 -4
  31. package/dist/movement/controller.js.map +1 -1
  32. package/dist/net/adapter.d.ts +3 -14
  33. package/dist/net/adapter.d.ts.map +1 -1
  34. package/dist/net/adapter.js.map +1 -1
  35. package/dist/net/presence.d.ts +68 -0
  36. package/dist/net/presence.d.ts.map +1 -0
  37. package/dist/net/presence.js +425 -0
  38. package/dist/net/presence.js.map +1 -0
  39. package/dist/player/avatar.d.ts +4 -0
  40. package/dist/player/avatar.d.ts.map +1 -1
  41. package/dist/player/avatar.js +97 -4
  42. package/dist/player/avatar.js.map +1 -1
  43. package/dist/player/player.d.ts +13 -0
  44. package/dist/player/player.d.ts.map +1 -1
  45. package/dist/player/player.js +44 -5
  46. package/dist/player/player.js.map +1 -1
  47. package/dist/portals/portals.d.ts +4 -1
  48. package/dist/portals/portals.d.ts.map +1 -1
  49. package/dist/portals/portals.js +6 -2
  50. package/dist/portals/portals.js.map +1 -1
  51. package/dist/types.d.ts +78 -4
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/ui/overlay.d.ts +7 -0
  54. package/dist/ui/overlay.d.ts.map +1 -1
  55. package/dist/ui/overlay.js +62 -7
  56. package/dist/ui/overlay.js.map +1 -1
  57. package/package.json +4 -1
  58. package/src/avatar/descriptor.ts +56 -0
  59. package/src/avatar/handoff.ts +91 -0
  60. package/src/avatar/loader.ts +184 -0
  61. package/src/controls/input.ts +61 -2
  62. package/src/controls/touch.ts +5 -0
  63. package/src/core/worldmesh.ts +110 -8
  64. package/src/index.ts +21 -1
  65. package/src/movement/controller.ts +59 -5
  66. package/src/net/adapter.ts +3 -14
  67. package/src/net/presence.ts +498 -0
  68. package/src/player/avatar.ts +109 -4
  69. package/src/player/player.ts +42 -3
  70. package/src/portals/portals.ts +6 -2
  71. package/src/types.ts +77 -4
  72. package/src/ui/overlay.ts +60 -7
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -7,12 +7,19 @@ import type { UiOptions } from '../types.js';
7
7
  export declare class Overlay {
8
8
  readonly root: HTMLDivElement;
9
9
  private prompt;
10
+ private lock;
10
11
  private onEnter;
12
+ private deferLockPanel;
11
13
  constructor(options: UiOptions & {
12
14
  onEnter: (touch?: boolean) => void;
13
15
  onInteract?: () => void;
14
16
  });
17
+ /** The pause screen, with the control list, is on screen. */
18
+ isPaused(): boolean;
15
19
  setLocked(locked: boolean): void;
20
+ /** Keep the full-screen click target; strip the dimmer and copy. */
21
+ private hideLockChrome;
22
+ private showLockChrome;
16
23
  setPrompt(text: string | null): void;
17
24
  dispose(): void;
18
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/ui/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmQ7C;;;;GAIG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAA4B;gBAGzC,OAAO,EAAE,SAAS,GAAG;QACnB,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;QACnC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;KACzB;IAoGH,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAIhC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IASpC,OAAO,IAAI,IAAI;CAGhB"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/ui/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA+Q7C;;;;GAIG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,cAAc,CAAU;gBAG9B,OAAO,EAAE,SAAS,GAAG;QACnB,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;QACnC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;KACzB;IAiHH,6DAA6D;IAC7D,QAAQ,IAAI,OAAO;IAInB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAQhC,oEAAoE;IACpE,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,cAAc;IAQtB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IASpC,OAAO,IAAI,IAAI;CAGhB"}
@@ -44,6 +44,14 @@ const CSS = `
44
44
  -webkit-tap-highlight-color: transparent;
45
45
  }
46
46
  .wm-overlay[data-locked="true"] .wm-lock { display: none; }
47
+ /* First visit with deferLockPanel: keep the click target, hide the chrome. */
48
+ .wm-overlay[data-defer-lock="true"]:not([data-lock-ready="true"]) .wm-lock {
49
+ background: transparent;
50
+ backdrop-filter: none;
51
+ }
52
+ .wm-overlay[data-defer-lock="true"]:not([data-lock-ready="true"]) .wm-lock-content {
53
+ visibility: hidden;
54
+ }
47
55
  .wm-lock-content {
48
56
  margin: auto 0;
49
57
  width: 100%;
@@ -56,10 +64,14 @@ const CSS = `
56
64
  box-sizing: border-box;
57
65
  }
58
66
  .wm-lock-title {
67
+ width: 100%;
68
+ margin: 0;
69
+ padding: 0;
70
+ display: block;
71
+ text-align: center;
59
72
  font-size: clamp(22px, 5vw, 34px);
60
73
  font-weight: 600;
61
74
  letter-spacing: .01em;
62
- margin: 0;
63
75
  }
64
76
  .wm-lock-cta {
65
77
  font-size: 13.5px;
@@ -260,14 +272,20 @@ const KEY_LEGEND = [
260
272
  export class Overlay {
261
273
  root;
262
274
  prompt;
275
+ lock;
263
276
  onEnter;
277
+ deferLockPanel;
264
278
  constructor(options) {
265
279
  injectStyles();
266
280
  this.onEnter = options.onEnter;
281
+ this.deferLockPanel = options.deferLockPanel === true;
267
282
  const isTouch = isTouchDevice();
268
283
  this.root = document.createElement('div');
269
284
  this.root.className = 'wm-overlay';
270
- this.root.dataset.locked = 'false';
285
+ // Already walking: no click-to-enter layer. Esc is what brings the pause screen up.
286
+ this.root.dataset.locked = options.moveBeforeLock ? 'true' : 'false';
287
+ if (this.deferLockPanel)
288
+ this.root.dataset.deferLock = 'true';
271
289
  if (options.crosshair !== false) {
272
290
  const crosshair = document.createElement('div');
273
291
  crosshair.className = 'wm-crosshair';
@@ -275,6 +293,7 @@ export class Overlay {
275
293
  }
276
294
  const lock = document.createElement('div');
277
295
  lock.className = 'wm-lock';
296
+ this.lock = lock;
278
297
  const content = document.createElement('div');
279
298
  content.className = 'wm-lock-content';
280
299
  const title = document.createElement('h1');
@@ -284,19 +303,28 @@ export class Overlay {
284
303
  const cta = document.createElement('button');
285
304
  cta.type = 'button';
286
305
  cta.className = 'wm-lock-cta';
287
- cta.textContent = isTouch ? 'Tap to enter' : 'Click to enter';
306
+ cta.textContent = 'Continue';
288
307
  content.appendChild(cta);
289
308
  const handleEnter = (e) => {
290
- e.preventDefault();
291
309
  e.stopPropagation();
292
310
  const touchInitiated = ('pointerType' in e && e.pointerType === 'touch') ||
293
311
  e.type === 'touchend' ||
294
312
  isTouch;
295
313
  this.onEnter(touchInitiated);
296
314
  };
315
+ // A click or tap on the button resumes. The Enter key does not: that key talks.
316
+ cta.addEventListener('keydown', (event) => {
317
+ if (event.key === 'Enter' || event.key === ' ')
318
+ event.preventDefault();
319
+ });
297
320
  cta.addEventListener('click', handleEnter);
298
- cta.addEventListener('pointerup', handleEnter);
299
- lock.addEventListener('click', handleEnter);
321
+ lock.addEventListener('click', (event) => {
322
+ const target = event.target;
323
+ if (target instanceof Element && target.closest('button, a, input, textarea, select, label, .walk-pause-actions')) {
324
+ return;
325
+ }
326
+ handleEnter(event);
327
+ });
300
328
  if (options.controlsHint !== false) {
301
329
  const keys = document.createElement('div');
302
330
  keys.className = 'wm-keys';
@@ -319,6 +347,8 @@ export class Overlay {
319
347
  }
320
348
  lock.appendChild(content);
321
349
  this.root.appendChild(lock);
350
+ if (this.deferLockPanel)
351
+ this.hideLockChrome();
322
352
  this.prompt = document.createElement('div');
323
353
  this.prompt.className = 'wm-prompt';
324
354
  this.prompt.dataset.visible = 'false';
@@ -340,12 +370,37 @@ export class Overlay {
340
370
  }
341
371
  const hint = document.createElement('div');
342
372
  hint.className = 'wm-hint';
343
- hint.textContent = isTouch ? 'Tap ⏸ to pause' : 'ESC to release cursor';
373
+ hint.textContent = isTouch ? 'Tap ⏸ to open the menu' : 'Esc to open the menu';
344
374
  this.root.appendChild(hint);
345
375
  document.body.appendChild(this.root);
346
376
  }
377
+ /** The pause screen, with the control list, is on screen. */
378
+ isPaused() {
379
+ return this.root.dataset.lockReady === 'true' && this.root.dataset.locked !== 'true';
380
+ }
347
381
  setLocked(locked) {
348
382
  this.root.dataset.locked = String(locked);
383
+ if (!locked && this.deferLockPanel) {
384
+ this.root.dataset.lockReady = 'true';
385
+ this.showLockChrome();
386
+ }
387
+ }
388
+ /** Keep the full-screen click target; strip the dimmer and copy. */
389
+ hideLockChrome() {
390
+ this.lock.style.background = 'transparent';
391
+ this.lock.style.backdropFilter = 'none';
392
+ this.lock.style.setProperty('-webkit-backdrop-filter', 'none');
393
+ const content = this.lock.querySelector('.wm-lock-content');
394
+ if (content instanceof HTMLElement)
395
+ content.style.visibility = 'hidden';
396
+ }
397
+ showLockChrome() {
398
+ this.lock.style.background = '';
399
+ this.lock.style.backdropFilter = '';
400
+ this.lock.style.removeProperty('-webkit-backdrop-filter');
401
+ const content = this.lock.querySelector('.wm-lock-content');
402
+ if (content instanceof HTMLElement)
403
+ content.style.visibility = '';
349
404
  }
350
405
  setPrompt(text) {
351
406
  if (!text) {
@@ -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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worldmesh/runtime",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "The shared WorldMesh navigation runtime: controls, movement, camera, player, abilities and portals.",
5
5
  "keywords": [
6
6
  "worldmesh",
@@ -53,6 +53,9 @@
53
53
  "typecheck": "tsc -p tsconfig.json",
54
54
  "prepare": "npm run build"
55
55
  },
56
+ "dependencies": {
57
+ "@pixiv/three-vrm": "^3.5.5"
58
+ },
56
59
  "peerDependencies": {
57
60
  "three": ">=0.160.0"
58
61
  },
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The only thing the runtime knows about external avatars: a normalized
3
+ * descriptor pointing at a model file the avatar's platform hosts. How it was
4
+ * found (which platform, which account, which OAuth flow) stays with whoever
5
+ * produced it — the WorldMesh hub's Avatar Wallet, or the world itself.
6
+ */
7
+
8
+ export type AvatarFormat = 'vrm' | 'glb' | 'gltf';
9
+
10
+ export interface AvatarDescriptor {
11
+ /** Where the avatar lives, e.g. 'vroid' or 'atproto'. Informational. */
12
+ provider: string;
13
+ /** The platform's id for the avatar. Informational. */
14
+ avatarId: string;
15
+ name: string | null;
16
+ thumbnail: string | null;
17
+ format: AvatarFormat;
18
+ /** The model file, on the platform's own storage. May be short-lived. */
19
+ modelUrl: string;
20
+ /** When `modelUrl` stops working (ISO 8601), or null. */
21
+ expiresAt: string | null;
22
+ /** The avatar's public page, for credit where its license asks for it. */
23
+ sourceUrl: string | null;
24
+ }
25
+
26
+ const FORMATS: readonly string[] = ['vrm', 'glb', 'gltf'];
27
+
28
+ /** Model URLs must be https, except on a local development machine. */
29
+ export function isLoadableUrl(raw: unknown): raw is string {
30
+ if (typeof raw !== 'string') return false;
31
+ try {
32
+ const url = new URL(raw);
33
+ if (url.protocol === 'https:') return true;
34
+ return url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ /** Accepts a descriptor from the network only if it has the right shape. */
41
+ export function parseAvatarDescriptor(value: unknown): AvatarDescriptor | null {
42
+ if (!value || typeof value !== 'object') return null;
43
+ const d = value as Record<string, unknown>;
44
+ if (typeof d.format !== 'string' || !FORMATS.includes(d.format) || !isLoadableUrl(d.modelUrl)) return null;
45
+ const text = (v: unknown) => (typeof v === 'string' ? v : null);
46
+ return {
47
+ provider: text(d.provider) ?? 'unknown',
48
+ avatarId: text(d.avatarId) ?? '',
49
+ name: text(d.name),
50
+ thumbnail: isLoadableUrl(d.thumbnail) ? d.thumbnail : null,
51
+ format: d.format as AvatarFormat,
52
+ modelUrl: d.modelUrl,
53
+ expiresAt: text(d.expiresAt),
54
+ sourceUrl: isLoadableUrl(d.sourceUrl) ? d.sourceUrl : null,
55
+ };
56
+ }
@@ -0,0 +1,91 @@
1
+ import { parseAvatarDescriptor, type AvatarDescriptor } from './descriptor.js';
2
+
3
+ /**
4
+ * Carrying a visitor's chosen avatar between worlds.
5
+ *
6
+ * The WorldMesh hub appends an opaque, short-lived ticket to a world's URL as
7
+ * a fragment (`#wm-avatar=…`): fragments are never sent to servers or in
8
+ * Referer headers. The runtime takes it out of the address bar (so it is not
9
+ * bookmarked or shared), keeps it in sessionStorage for this tab, and adds it
10
+ * again to portal destinations so the avatar follows the visitor.
11
+ *
12
+ * A ticket only ever resolves to an avatar descriptor. It carries no session,
13
+ * no account and no platform credentials.
14
+ */
15
+
16
+ export const AVATAR_TICKET_PARAM = 'wm-avatar';
17
+ /** sessionStorage key. The hub writes the same key. */
18
+ export const AVATAR_TICKET_STORAGE_KEY = 'worldmesh.avatarTicket';
19
+ const TICKET_PATTERN = /^[A-Za-z0-9_-]{16,256}\.[A-Za-z0-9_-]{16,512}$/;
20
+
21
+ /** Moves a ticket from this page's URL fragment into storage, and returns the current one. */
22
+ export function takeAvatarTicket(): string | null {
23
+ const hash = window.location.hash.slice(1);
24
+ if (hash) {
25
+ const params = new URLSearchParams(hash);
26
+ const ticket = params.get(AVATAR_TICKET_PARAM);
27
+ if (ticket !== null) {
28
+ params.delete(AVATAR_TICKET_PARAM);
29
+ const rest = params.toString();
30
+ history.replaceState(history.state, '', `${window.location.pathname}${window.location.search}${rest ? `#${rest}` : ''}`);
31
+ if (TICKET_PATTERN.test(ticket)) setAvatarTicket(ticket);
32
+ }
33
+ }
34
+ return getAvatarTicket();
35
+ }
36
+
37
+ export function getAvatarTicket(): string | null {
38
+ try {
39
+ const ticket = sessionStorage.getItem(AVATAR_TICKET_STORAGE_KEY);
40
+ return ticket && TICKET_PATTERN.test(ticket) ? ticket : null;
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ export function setAvatarTicket(ticket: string | null): void {
47
+ try {
48
+ if (ticket) sessionStorage.setItem(AVATAR_TICKET_STORAGE_KEY, ticket);
49
+ else sessionStorage.removeItem(AVATAR_TICKET_STORAGE_KEY);
50
+ } catch {
51
+ // Storage blocked: the avatar simply does not follow to the next world.
52
+ }
53
+ }
54
+
55
+ /** Adds the current ticket to a destination URL's fragment, unless it already has one. */
56
+ export function withAvatarTicket(url: URL): URL {
57
+ const ticket = getAvatarTicket();
58
+ if (ticket && !url.hash && /^https?:$/.test(url.protocol)) {
59
+ url.hash = `${AVATAR_TICKET_PARAM}=${ticket}`;
60
+ }
61
+ return url;
62
+ }
63
+
64
+ /**
65
+ * Exchanges a ticket at the hub for a descriptor. Sends no cookies and no
66
+ * credentials. Null when the visitor has not chosen an avatar, the ticket has
67
+ * expired, or the hub cannot be reached.
68
+ */
69
+ export async function resolveWorldMeshAvatar(hubUrl: string, ticket: string, timeoutMs = 10_000): Promise<AvatarDescriptor | null> {
70
+ const controller = new AbortController();
71
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
72
+ try {
73
+ const response = await fetch(new URL('/api/account/avatar/resolve', hubUrl), {
74
+ method: 'POST',
75
+ mode: 'cors',
76
+ credentials: 'omit',
77
+ headers: { 'Content-Type': 'application/json' },
78
+ body: JSON.stringify({ ticket }),
79
+ signal: controller.signal,
80
+ });
81
+ if (response.status === 401) {
82
+ setAvatarTicket(null);
83
+ return null;
84
+ }
85
+ if (!response.ok) return null;
86
+ const body = (await response.json()) as { avatar?: unknown };
87
+ return parseAvatarDescriptor(body.avatar);
88
+ } finally {
89
+ clearTimeout(timer);
90
+ }
91
+ }
@@ -0,0 +1,184 @@
1
+ import { AnimationMixer, Box3, Group, MathUtils, Mesh, Texture, type AnimationAction, type Object3D } from 'three';
2
+ import type { AvatarMotion } from '../player/avatar.js';
3
+ import type { AvatarDescriptor } from './descriptor.js';
4
+
5
+ /** A loaded external avatar, normalised to the WorldMesh body convention. */
6
+ export interface LoadedAvatar {
7
+ /** Feet at y = 0, facing -Z, scaled to the player's height. */
8
+ object: Object3D;
9
+ /** Call once per frame with how the player moves. */
10
+ animate(motion: AvatarMotion): void;
11
+ dispose(): void;
12
+ }
13
+
14
+ export interface LoadAvatarOptions {
15
+ /** Standing height to scale the model to, in metres. */
16
+ height: number;
17
+ /** Refuse models larger than this. Defaults to 40 MB. */
18
+ maxBytes?: number;
19
+ signal?: AbortSignal;
20
+ }
21
+
22
+ /**
23
+ * Downloads a VRM / glTF model straight from the URL in the descriptor (the
24
+ * avatar platform's own storage) and turns it into a player body. The loaders
25
+ * are imported on first use, so worlds that never show an external avatar
26
+ * never download them.
27
+ */
28
+ export async function loadAvatarModel(descriptor: AvatarDescriptor, options: LoadAvatarOptions): Promise<LoadedAvatar> {
29
+ const buffer = await download(descriptor.modelUrl, options.maxBytes ?? 40 * 1024 * 1024, options.signal);
30
+ const [{ GLTFLoader }, vrmModule] = await Promise.all([
31
+ import('three/examples/jsm/loaders/GLTFLoader.js'),
32
+ descriptor.format === 'vrm' ? import('@pixiv/three-vrm') : Promise.resolve(null),
33
+ ]);
34
+ const loader = new GLTFLoader();
35
+ if (vrmModule) loader.register((parser) => new vrmModule.VRMLoaderPlugin(parser));
36
+ const gltf = await loader.parseAsync(buffer, '');
37
+
38
+ const vrm = vrmModule ? (gltf.userData.vrm as import('@pixiv/three-vrm').VRM | undefined) : undefined;
39
+ if (descriptor.format === 'vrm' && (!vrm || !vrmModule)) throw new Error('Not a VRM model');
40
+ const model = vrm ? vrm.scene : gltf.scene;
41
+ if (vrm && vrmModule) {
42
+ vrmModule.VRMUtils.removeUnnecessaryVertices(model);
43
+ vrmModule.VRMUtils.combineSkeletons(model);
44
+ // VRM 0.x faces -Z; this makes it face +Z like VRM 1.0 and plain glTF.
45
+ vrmModule.VRMUtils.rotateVRM0(vrm);
46
+ }
47
+ model.traverse((child) => {
48
+ // Skinned meshes are bounded by their rest pose; animated limbs would pop out of view.
49
+ child.frustumCulled = false;
50
+ if ((child as Mesh).isMesh) child.castShadow = true;
51
+ });
52
+
53
+ // glTF and VRM face +Z; WorldMesh bodies face -Z. Scale to the player and
54
+ // stand the feet on y = 0.
55
+ const root = new Group();
56
+ root.name = 'worldmesh:external-avatar';
57
+ const turn = new Group();
58
+ turn.rotation.y = Math.PI;
59
+ turn.add(model);
60
+ root.add(turn);
61
+ root.updateMatrixWorld(true);
62
+ const box = new Box3().setFromObject(root);
63
+ const modelHeight = box.max.y - box.min.y;
64
+ if (!(modelHeight > 0.05 && modelHeight < 100)) throw new Error('Model has no usable size');
65
+ const scale = options.height / modelHeight;
66
+ turn.scale.setScalar(scale);
67
+ turn.position.y = -box.min.y * scale;
68
+
69
+ const animate = vrm ? vrmAnimator(vrm) : clipAnimator(model, gltf.animations);
70
+ return {
71
+ object: root,
72
+ animate,
73
+ dispose() {
74
+ if (vrm && vrmModule) vrmModule.VRMUtils.deepDispose(model);
75
+ else disposeTree(model);
76
+ },
77
+ };
78
+ }
79
+
80
+ async function download(url: string, maxBytes: number, signal?: AbortSignal): Promise<ArrayBuffer> {
81
+ const response = await fetch(url, { mode: 'cors', credentials: 'omit', referrerPolicy: 'no-referrer', signal });
82
+ if (!response.ok) throw new Error(`Model download failed (${response.status})`);
83
+ if (Number(response.headers.get('Content-Length') ?? '0') > maxBytes) throw new Error('Model is too large');
84
+ if (!response.body) return response.arrayBuffer();
85
+ const reader = response.body.getReader();
86
+ const chunks: Uint8Array[] = [];
87
+ let size = 0;
88
+ for (;;) {
89
+ const { done, value } = await reader.read();
90
+ if (done) break;
91
+ size += value.byteLength;
92
+ if (size > maxBytes) {
93
+ await reader.cancel();
94
+ throw new Error('Model is too large');
95
+ }
96
+ chunks.push(value);
97
+ }
98
+ const bytes = new Uint8Array(size);
99
+ let offset = 0;
100
+ for (const chunk of chunks) {
101
+ bytes.set(chunk, offset);
102
+ offset += chunk.byteLength;
103
+ }
104
+ return bytes.buffer;
105
+ }
106
+
107
+ /**
108
+ * VRMs arrive in a T-pose with no animation. Lower the arms and swing arms
109
+ * and legs with speed, through the normalised humanoid rig so it works for
110
+ * any VRM, then let spring bones (hair, clothes) follow.
111
+ */
112
+ function vrmAnimator(vrm: import('@pixiv/three-vrm').VRM): (motion: AvatarMotion) => void {
113
+ const bone = (name: Parameters<NonNullable<typeof vrm.humanoid>['getNormalizedBoneNode']>[0]) =>
114
+ vrm.humanoid?.getNormalizedBoneNode(name) ?? null;
115
+ const armL = bone('leftUpperArm');
116
+ const armR = bone('rightUpperArm');
117
+ const foreArmL = bone('leftLowerArm');
118
+ const foreArmR = bone('rightLowerArm');
119
+ const legL = bone('leftUpperLeg');
120
+ const legR = bone('rightUpperLeg');
121
+ const kneeL = bone('leftLowerLeg');
122
+ const kneeR = bone('rightLowerLeg');
123
+ // VRM 0.x rigs are mirrored on X and Z relative to VRM 1.0.
124
+ const mirror = vrm.meta?.metaVersion === '0' ? -1 : 1;
125
+ let phase = 0;
126
+ let stride = 0;
127
+ let air = 0;
128
+
129
+ return (motion) => {
130
+ if (motion.dt <= 0) return;
131
+ const blend = 1 - Math.exp(-motion.dt * 10);
132
+ const walking = motion.grounded ? MathUtils.clamp(motion.speed / 4.5, 0, 1) : 0;
133
+ stride += (walking - stride) * blend;
134
+ air += ((motion.grounded ? 0 : 1) - air) * blend;
135
+ phase += motion.dt * (4 + motion.speed * 1.2) * (stride > 0.01 ? 1 : 0);
136
+ const swing = Math.sin(phase) * 0.6 * stride;
137
+
138
+ const armDown = 1.2 - air * 0.5;
139
+ if (armL) armL.rotation.set(mirror * swing * 0.7, 0, mirror * -armDown);
140
+ if (armR) armR.rotation.set(mirror * -swing * 0.7, 0, mirror * armDown);
141
+ if (foreArmL) foreArmL.rotation.set(0, 0, mirror * -0.15);
142
+ if (foreArmR) foreArmR.rotation.set(0, 0, mirror * 0.15);
143
+ if (legL) legL.rotation.set(mirror * (-swing - air * 0.3), 0, 0);
144
+ if (legR) legR.rotation.set(mirror * (swing - air * 0.1), 0, 0);
145
+ if (kneeL) kneeL.rotation.set(mirror * (Math.max(0, swing) * 0.8 + air * 0.4), 0, 0);
146
+ if (kneeR) kneeR.rotation.set(mirror * (Math.max(0, -swing) * 0.8 + air * 0.2), 0, 0);
147
+ vrm.update(motion.dt);
148
+ };
149
+ }
150
+
151
+ /** Plain glTF bodies: play an idle clip, and a walk/run clip while moving, if the file has them. */
152
+ function clipAnimator(model: Object3D, clips: import('three').AnimationClip[]): (motion: AvatarMotion) => void {
153
+ if (!clips.length) return () => {};
154
+ const mixer = new AnimationMixer(model);
155
+ const find = (pattern: RegExp) => clips.find((clip) => pattern.test(clip.name));
156
+ const idleClip = find(/idle|stand|breath/i) ?? clips[0];
157
+ const walkClip = find(/walk|run|jog/i);
158
+ const idle = mixer.clipAction(idleClip).play();
159
+ const walk: AnimationAction | null = walkClip && walkClip !== idleClip ? mixer.clipAction(walkClip) : null;
160
+ let moving = false;
161
+ return (motion) => {
162
+ const nowMoving = motion.grounded && motion.speed > 0.5;
163
+ if (walk && nowMoving !== moving) {
164
+ moving = nowMoving;
165
+ const [from, to] = moving ? [idle, walk] : [walk, idle];
166
+ to.reset().play();
167
+ from.crossFadeTo(to, 0.2, false);
168
+ }
169
+ mixer.update(motion.dt);
170
+ };
171
+ }
172
+
173
+ function disposeTree(root: Object3D): void {
174
+ root.traverse((child) => {
175
+ if (!(child instanceof Mesh)) return;
176
+ child.geometry.dispose();
177
+ for (const material of Array.isArray(child.material) ? child.material : [child.material]) {
178
+ for (const value of Object.values(material)) {
179
+ if (value instanceof Texture) value.dispose();
180
+ }
181
+ material.dispose();
182
+ }
183
+ });
184
+ }