@diffenderfer-games/hub 2.0.0-next.6 → 2.0.0-next.7

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 (38) hide show
  1. package/CHANGELOG.md +39 -28
  2. package/dist/avatar-pixi.js +1 -1
  3. package/dist/avatar-svg.js +1 -1
  4. package/dist/avatar.d.ts +2 -2
  5. package/dist/avatar.js +3 -3
  6. package/dist/doctor/cli.mjs +1 -1
  7. package/dist/shared/art.js +145 -3
  8. package/dist/shared/art.js.map +1 -1
  9. package/dist/shared/avatar.d.ts +3 -3
  10. package/dist/shared/client-version.gen.js +1 -1
  11. package/dist/shared/daily.js +1 -1
  12. package/dist/shared/describe.d.ts.map +1 -1
  13. package/dist/shared/describe.js +9 -1
  14. package/dist/shared/describe.js.map +1 -1
  15. package/dist/shared/index.d.ts +2 -2
  16. package/dist/shared/live-canvas.js +1 -1
  17. package/dist/shared/overlays.js +1 -1
  18. package/dist/shared/pose-key.js +1 -1
  19. package/dist/shared/svg-markup.js +112 -27
  20. package/dist/shared/svg-markup.js.map +1 -1
  21. package/dist/shared/svg.js +1 -1
  22. package/package.json +2 -2
  23. package/src/avatar/adapters/pixi-crowd.ts +302 -302
  24. package/src/avatar/adapters/pixi-types.ts +84 -84
  25. package/src/avatar/adapters/three.ts +126 -126
  26. package/src/avatar/art/glasses.ts +61 -3
  27. package/src/avatar/art/shape.ts +22 -3
  28. package/src/avatar/describe.ts +4 -1
  29. package/src/avatar/geom.ts +5 -0
  30. package/src/avatar/render/compose.ts +67 -22
  31. package/src/avatar/render/eyewear.ts +75 -13
  32. package/src/avatar-three.ts +18 -18
  33. package/src/avatar.ts +2 -2
  34. package/src/core/avatar/hub-avatar.ts +308 -308
  35. package/src/core/hub-progress.ts +269 -269
  36. package/src/core/page-account.ts +121 -121
  37. package/src/core/version/client-version.gen.ts +1 -1
  38. package/src/overlay/overlay.ts +3 -3
@@ -1,121 +1,121 @@
1
- /**
2
- * Who the page is signed in as, as the hub tells it, so `hub.userId()` and
3
- * `hub.avatar` follow the account without the game calling `hub.me()`:
4
- *
5
- * - the menu's `hub:account` (every refresh: after it makes a new guest's
6
- * account, after sign-in) and `hub:auth` (the account changed);
7
- * - the social runtime's {@link SESSION_EVENT} each time its socket says
8
- * hello (connected, or connected again after a drop);
9
- * - this client's own sign-in, sign-up, claim and sign-out.
10
- *
11
- * One per page: every bundle's copy hears the same window events.
12
- */
13
- import { readField } from '../realtime/cross-bundle';
14
- import { SESSION_EVENT } from '../realtime/runtime-api';
15
- import { isBrowserPage } from './page';
16
-
17
- /** The window events that say who is signed in (`{ user }`). */
18
- const ACCOUNT_EVENTS = ['hub:account', 'hub:auth'] as const;
19
-
20
- /** The signed-in player as the page heard it. */
21
- export interface PageUser {
22
- readonly id: number;
23
- /** Their look code when the source carried it, else `null`. */
24
- readonly look: string | null;
25
- }
26
-
27
- /** Where the news came from: an account event, or a socket hello (a time to catch up on what was missed). */
28
- export type AccountSource = 'account' | 'session';
29
-
30
- /** Hears every report of who is signed in. */
31
- export type AccountListener = (user: PageUser | null, source: AccountSource) => void;
32
-
33
- /** The page's account, as last heard. */
34
- export class PageAccount {
35
- /** `undefined` until something said; `null` when signed out. */
36
- private heard: PageUser | null | undefined = undefined;
37
- private readonly listeners = new Set<AccountListener>();
38
- private isListening = false;
39
-
40
- constructor() {
41
- this.listen();
42
- }
43
-
44
- /** The signed-in player, `null` when signed out, `undefined` before anything said. */
45
- get user(): PageUser | null | undefined {
46
- this.listen();
47
- return this.heard;
48
- }
49
-
50
- /** Record who is signed in (this client's own sign-in or sign-out) and tell the listeners. */
51
- note(user: PageUser | null, source: AccountSource = 'account'): void {
52
- this.heard = user;
53
- for (const listener of [...this.listeners]) {
54
- listener(user, source);
55
- }
56
- }
57
-
58
- /** Hear every report; returns the unsubscribe function. */
59
- on(listener: AccountListener): () => void {
60
- this.listen();
61
- this.listeners.add(listener);
62
- return () => {
63
- this.listeners.delete(listener);
64
- };
65
- }
66
-
67
- /** Listen to the window events (at once in a page; made before a window existed, on first use). */
68
- private listen(): void {
69
- if (this.isListening || !isBrowserPage()) {
70
- return;
71
- }
72
- this.isListening = true;
73
- for (const eventName of ACCOUNT_EVENTS) {
74
- window.addEventListener(eventName, (event) => { this.onEvent(event, 'account'); });
75
- }
76
- window.addEventListener(SESSION_EVENT, (event) => { this.onEvent(event, 'session'); });
77
- }
78
-
79
- private onEvent(event: Event, source: AccountSource): void {
80
- if (!(event instanceof CustomEvent)) {
81
- return;
82
- }
83
- const user = readUser(event.detail);
84
- if (user !== undefined) {
85
- this.note(user, source);
86
- }
87
- }
88
- }
89
-
90
- /** A page user from an account the hub sent (`look` when it has one). */
91
- export function toPageUser(user: { readonly id: number; readonly look?: string | undefined }): PageUser {
92
- return { id: user.id, look: lookOrNull(user.look) };
93
- }
94
-
95
- /** A non-empty look code, else `null`. */
96
- // eslint-disable-next-line no-restricted-syntax -- trust boundary: a field of another bundle's event detail
97
- function lookOrNull(look: unknown): string | null {
98
- return typeof look === 'string' && look !== '' ? look : null;
99
- }
100
-
101
- /** The user in a `{ user }` detail: the user, `null` (signed out), or `undefined` (it doesn't say). */
102
- // eslint-disable-next-line no-restricted-syntax -- trust boundary: another bundle's event detail, read field by field
103
- function readUser(detail: unknown): PageUser | null | undefined {
104
- const user = readField(detail, 'user');
105
- if (user === null) {
106
- return null;
107
- }
108
- const id = readField(user, 'id');
109
- if (typeof id !== 'number' || !Number.isInteger(id)) {
110
- return undefined;
111
- }
112
- return { id, look: lookOrNull(readField(user, 'look')) };
113
- }
114
-
115
- let pageAccountSingleton: PageAccount | null = null;
116
-
117
- /** The page's account tracker (made on first use; the hub client makes it at load). */
118
- export function pageAccount(): PageAccount {
119
- pageAccountSingleton ??= new PageAccount();
120
- return pageAccountSingleton;
121
- }
1
+ /**
2
+ * Who the page is signed in as, as the hub tells it, so `hub.userId()` and
3
+ * `hub.avatar` follow the account without the game calling `hub.me()`:
4
+ *
5
+ * - the menu's `hub:account` (every refresh: after it makes a new guest's
6
+ * account, after sign-in) and `hub:auth` (the account changed);
7
+ * - the social runtime's {@link SESSION_EVENT} each time its socket says
8
+ * hello (connected, or connected again after a drop);
9
+ * - this client's own sign-in, sign-up, claim and sign-out.
10
+ *
11
+ * One per page: every bundle's copy hears the same window events.
12
+ */
13
+ import { readField } from '../realtime/cross-bundle';
14
+ import { SESSION_EVENT } from '../realtime/runtime-api';
15
+ import { isBrowserPage } from './page';
16
+
17
+ /** The window events that say who is signed in (`{ user }`). */
18
+ const ACCOUNT_EVENTS = ['hub:account', 'hub:auth'] as const;
19
+
20
+ /** The signed-in player as the page heard it. */
21
+ export interface PageUser {
22
+ readonly id: number;
23
+ /** Their look code when the source carried it, else `null`. */
24
+ readonly look: string | null;
25
+ }
26
+
27
+ /** Where the news came from: an account event, or a socket hello (a time to catch up on what was missed). */
28
+ export type AccountSource = 'account' | 'session';
29
+
30
+ /** Hears every report of who is signed in. */
31
+ export type AccountListener = (user: PageUser | null, source: AccountSource) => void;
32
+
33
+ /** The page's account, as last heard. */
34
+ export class PageAccount {
35
+ /** `undefined` until something said; `null` when signed out. */
36
+ private heard: PageUser | null | undefined = undefined;
37
+ private readonly listeners = new Set<AccountListener>();
38
+ private isListening = false;
39
+
40
+ constructor() {
41
+ this.listen();
42
+ }
43
+
44
+ /** The signed-in player, `null` when signed out, `undefined` before anything said. */
45
+ get user(): PageUser | null | undefined {
46
+ this.listen();
47
+ return this.heard;
48
+ }
49
+
50
+ /** Record who is signed in (this client's own sign-in or sign-out) and tell the listeners. */
51
+ note(user: PageUser | null, source: AccountSource = 'account'): void {
52
+ this.heard = user;
53
+ for (const listener of [...this.listeners]) {
54
+ listener(user, source);
55
+ }
56
+ }
57
+
58
+ /** Hear every report; returns the unsubscribe function. */
59
+ on(listener: AccountListener): () => void {
60
+ this.listen();
61
+ this.listeners.add(listener);
62
+ return () => {
63
+ this.listeners.delete(listener);
64
+ };
65
+ }
66
+
67
+ /** Listen to the window events (at once in a page; made before a window existed, on first use). */
68
+ private listen(): void {
69
+ if (this.isListening || !isBrowserPage()) {
70
+ return;
71
+ }
72
+ this.isListening = true;
73
+ for (const eventName of ACCOUNT_EVENTS) {
74
+ window.addEventListener(eventName, (event) => { this.onEvent(event, 'account'); });
75
+ }
76
+ window.addEventListener(SESSION_EVENT, (event) => { this.onEvent(event, 'session'); });
77
+ }
78
+
79
+ private onEvent(event: Event, source: AccountSource): void {
80
+ if (!(event instanceof CustomEvent)) {
81
+ return;
82
+ }
83
+ const user = readUser(event.detail);
84
+ if (user !== undefined) {
85
+ this.note(user, source);
86
+ }
87
+ }
88
+ }
89
+
90
+ /** A page user from an account the hub sent (`look` when it has one). */
91
+ export function toPageUser(user: { readonly id: number; readonly look?: string | undefined }): PageUser {
92
+ return { id: user.id, look: lookOrNull(user.look) };
93
+ }
94
+
95
+ /** A non-empty look code, else `null`. */
96
+ // eslint-disable-next-line no-restricted-syntax -- trust boundary: a field of another bundle's event detail
97
+ function lookOrNull(look: unknown): string | null {
98
+ return typeof look === 'string' && look !== '' ? look : null;
99
+ }
100
+
101
+ /** The user in a `{ user }` detail: the user, `null` (signed out), or `undefined` (it doesn't say). */
102
+ // eslint-disable-next-line no-restricted-syntax -- trust boundary: another bundle's event detail, read field by field
103
+ function readUser(detail: unknown): PageUser | null | undefined {
104
+ const user = readField(detail, 'user');
105
+ if (user === null) {
106
+ return null;
107
+ }
108
+ const id = readField(user, 'id');
109
+ if (typeof id !== 'number' || !Number.isInteger(id)) {
110
+ return undefined;
111
+ }
112
+ return { id, look: lookOrNull(readField(user, 'look')) };
113
+ }
114
+
115
+ let pageAccountSingleton: PageAccount | null = null;
116
+
117
+ /** The page's account tracker (made on first use; the hub client makes it at load). */
118
+ export function pageAccount(): PageAccount {
119
+ pageAccountSingleton ??= new PageAccount();
120
+ return pageAccountSingleton;
121
+ }
@@ -1,3 +1,3 @@
1
1
  // Generated by tools/hub-client/generate.ts. Do not edit; run `npm run gen:hub-client`.
2
2
  /** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
3
- export const HUB_CLIENT_VERSION = '2.0.0-next.6';
3
+ export const HUB_CLIENT_VERSION = '2.0.0-next.7';
@@ -215,9 +215,9 @@ export class Overlay implements NavHighlighter {
215
215
  }
216
216
  }
217
217
 
218
- /** Every inset side. */
219
- const INSET_SIDES: readonly (keyof Insets)[] = ['top', 'right', 'bottom', 'left'];
220
-
218
+ /** Every inset side. */
219
+ const INSET_SIDES: readonly (keyof Insets)[] = ['top', 'right', 'bottom', 'left'];
220
+
221
221
  /** The page-wide CSS variables other hub UI (the runtime's toasts) keeps clear of. */
222
222
  function publishInsets(insets: Partial<Insets>): void {
223
223
  if (typeof document === 'undefined') {