@linxin666/dsh-pet 0.3.24 → 0.3.25

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.i18n.yaml +2 -2
  2. package/README.md +4 -3
  3. package/README.zh.md +4 -3
  4. package/icon.svg +3 -0
  5. package/lib/client.js +522 -194
  6. package/lib/client.js.map +1 -1
  7. package/lib/index.js +706 -422
  8. package/lib/live2d-vendor.js +96 -96
  9. package/lib/live2d-vendor.js.map +1 -1
  10. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  11. package/lib/types/client/PetDockEntry.js +1 -1
  12. package/lib/types/client/PetSettingsCard.d.ts +20 -9
  13. package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
  14. package/lib/types/client/PetSettingsCard.js +116 -5
  15. package/lib/types/client/PetSprite.d.ts +6 -0
  16. package/lib/types/client/PetSprite.d.ts.map +1 -1
  17. package/lib/types/client/PetSprite.js +95 -0
  18. package/lib/types/client/PluginSettingsCard.d.ts +4 -0
  19. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
  20. package/lib/types/client/PluginSettingsCard.js +3 -2
  21. package/lib/types/client/gameplay-hud.d.ts +10 -1
  22. package/lib/types/client/gameplay-hud.d.ts.map +1 -1
  23. package/lib/types/client/gameplay-hud.js +137 -23
  24. package/lib/types/client/index.d.ts +8 -5
  25. package/lib/types/client/index.d.ts.map +1 -1
  26. package/lib/types/client/index.js +61 -27
  27. package/lib/types/client/main-session.d.ts +33 -0
  28. package/lib/types/client/main-session.d.ts.map +1 -0
  29. package/lib/types/client/main-session.js +34 -0
  30. package/lib/types/client/settings-form.d.ts +17 -17
  31. package/lib/types/client/settings-form.d.ts.map +1 -1
  32. package/lib/types/client/settings-form.js +30 -27
  33. package/lib/types/event-projection.d.ts.map +1 -1
  34. package/lib/types/event-projection.js +5 -3
  35. package/lib/types/gameplay.d.ts +79 -5
  36. package/lib/types/gameplay.d.ts.map +1 -1
  37. package/lib/types/gameplay.js +212 -17
  38. package/lib/types/http.d.ts +18 -1
  39. package/lib/types/http.d.ts.map +1 -1
  40. package/lib/types/http.js +22 -1
  41. package/lib/types/index.d.ts +100 -29
  42. package/lib/types/index.d.ts.map +1 -1
  43. package/lib/types/index.js +113 -64
  44. package/lib/types/persist.d.ts.map +1 -1
  45. package/lib/types/persist.js +3 -1
  46. package/lib/types/routes.d.ts.map +1 -1
  47. package/lib/types/routes.js +3 -1
  48. package/lib/types/service.d.ts +8 -3
  49. package/lib/types/service.d.ts.map +1 -1
  50. package/lib/types/service.js +26 -4
  51. package/package.json +46 -26
  52. package/src/client/PetDockEntry.tsx +1 -0
  53. package/src/client/PetSettingsCard.test.tsx +103 -0
  54. package/src/client/PetSettingsCard.tsx +129 -26
  55. package/src/client/PetSprite.tsx +96 -0
  56. package/src/client/PluginSettingsCard.tsx +7 -2
  57. package/src/client/gameplay-hud.test.tsx +106 -8
  58. package/src/client/gameplay-hud.tsx +143 -28
  59. package/src/client/index.test.tsx +37 -4
  60. package/src/client/index.ts +74 -34
  61. package/src/client/main-session.ts +43 -0
  62. package/src/client/settings-form.ts +34 -31
  63. package/src/event-projection.ts +5 -3
  64. package/src/gameplay.test.ts +138 -1
  65. package/src/gameplay.ts +253 -16
  66. package/src/http.ts +23 -1
  67. package/src/index.test.ts +107 -11
  68. package/src/index.ts +162 -73
  69. package/src/persist.ts +3 -1
  70. package/src/registry.test.ts +3 -2
  71. package/src/routes.ts +3 -1
  72. package/src/service.ts +27 -5
@@ -1 +1 @@
1
- {"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAItD,OAAO,EAAe,KAAK,WAAW,EAAoB,MAAM,oBAAoB,CAAA;AACpF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,2DAA2D;IAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,uGAAuG;IACvG,QAAQ,EAAE,WAAW,CAAA;CACtB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAIH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAyFnE"}
1
+ {"version":3,"file":"PetDockEntry.d.ts","sourceRoot":"","sources":["../../../src/client/PetDockEntry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAItD,OAAO,EAAe,KAAK,WAAW,EAAoB,MAAM,oBAAoB,CAAA;AACpF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,KAAK,EAAE,gBAAgB,CAAA;IACvB,kFAAkF;IAClF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAA;IACf,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,uBAAuB;IACvB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAChD,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,2DAA2D;IAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,uGAAuG;IACvG,QAAQ,EAAE,WAAW,CAAA;CACtB;AAED,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAC3B,WAAW,GACT,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAIH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA0FnE"}
@@ -47,7 +47,7 @@ export function PetDockEntry(props) {
47
47
  if (visible) {
48
48
  return (_jsx("span", { "data-pet-dock": true, "data-testid": "pet-dock", children: snapshot === null || definition === null
49
49
  ? null
50
- : (_jsx(PetRendererSwitch, { definition: definition, phase: snapshot?.phase ?? 'idle', onPet: props.pet, ...(aux === null ? {} : { drag: aux.drag, bus: aux.bus }), t: props.t, children: _jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onOpenSession: props.openSession, onFeedbackDone: props.feedbackDone, portalTarget: props.portalTarget, dragDisabled: snapshot.gameplay?.mode === 'work', ...(gameplay === undefined || aux === null
50
+ : (_jsx(PetRendererSwitch, { definition: definition, phase: snapshot?.phase ?? 'idle', onPet: props.pet, ...(aux === null ? {} : { drag: aux.drag, bus: aux.bus }), t: props.t, children: _jsx(PetSprite, { snapshot: snapshot, definition: definition, display: snapshot.display, feedback: feedback, onPet: props.pet, onFeed: props.feed, onHide: props.hide, onDragEnd: props.dragEnd, onRename: props.rename, onOpenSession: props.openSession, onFeedbackDone: props.feedbackDone, portalTarget: props.portalTarget, dragDisabled: snapshot.gameplay?.mode === 'work', ...(aux === null ? {} : { bus: aux.bus }), ...(gameplay === undefined || aux === null
51
51
  ? {}
52
52
  : {
53
53
  onGameplayTap: (fx, fy) => aux.bus.tap?.(fx, fy),
@@ -1,14 +1,16 @@
1
1
  /**
2
- * The pet settings card: pet selection plus display layout, bound to the
3
- * 'pet' settings namespace the host plugin registers. Rendered as an
4
- * always-open first-level settings page; the section wrapper below mounts it
5
- * as the content of the top-level 'settings.section' nav entry. The petId
6
- * choices come from the registry endpoint ('/api/pet/pets') — the same list
7
- * the sprite renders from — so the card carries no per-pet knowledge.
2
+ * The pet settings card: pet selection plus display layout, staged over the
3
+ * 'pet' profile entry's own configuration (a plugin's settings ARE its Cordis
4
+ * Config since 0.1.7, so the Host serves one form per profile entry).
5
+ * Rendered as an always-open first-level settings page; the section wrapper
6
+ * below mounts it as the content of the top-level 'settings.section' nav
7
+ * entry. The petId choices come from the registry endpoint ('/api/pet/pets') —
8
+ * the same list the sprite renders from — so the card carries no per-pet
9
+ * knowledge.
8
10
  */
9
11
  import type { ReactNode } from 'react';
10
12
  import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
11
- import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
13
+ import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
12
14
  import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
13
15
  import { type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts';
14
16
  /** The pet's settings fields this card edits (the namespace's full schema). */
@@ -32,6 +34,8 @@ export interface PetSettings {
32
34
  }
33
35
  /** What the pet settings card renders. */
34
36
  export interface PetSettingsCardState extends CardShell {
37
+ /** The aggregate shell has no Host settings form; pet selection uses its own persisted API. */
38
+ petSelectionFallback: boolean;
35
39
  /** Plugin master switch. */
36
40
  enabled: CardFieldState;
37
41
  /** Master switch. */
@@ -75,17 +79,24 @@ export declare class PetSettingsCardController {
75
79
  private readonly petChoices;
76
80
  private readonly petLabels;
77
81
  private diagnostics;
82
+ private selectedPetId;
83
+ private stagedPetId;
84
+ private savingPet;
85
+ private petSaveFailed;
78
86
  private loaded;
79
87
  private attempts;
80
88
  private disposed;
81
89
  /** Pending deferred-load or retry timer; cancelled by dispose(). */
82
90
  private pendingTimer;
83
- /** @param scope - the bound settings scope for the 'pet' namespace. */
84
- constructor(scope: SettingsScope<PetSettings>);
91
+ /** @param scope - the bound configuration form for the 'pet' entry. */
92
+ constructor(scope: ConfigForm<PetSettings>);
85
93
  /** Fetch registry diagnostics once (soft-fail: an empty list on error). */
86
94
  private loadDiagnostics;
87
95
  /** Resolve the registry choices once (retried a few times on failure). */
88
96
  private loadPets;
97
+ private loadSelectedPet;
98
+ private fallback;
99
+ private savePetSelection;
89
100
  private projection;
90
101
  /**
91
102
  * Build the face the card's slot registration injects.
@@ -1 +1 @@
1
- {"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"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"}
@@ -17,6 +17,16 @@ async function fetchPetDiagnostics() {
17
17
  const body = (await response.json());
18
18
  return body.diagnostics ?? [];
19
19
  }
20
+ /** Read the selection from the same persisted state the pet renders. */
21
+ async function fetchSelectedPetId() {
22
+ const response = await fetch('/api/pet/state');
23
+ if (!response.ok)
24
+ throw new Error('pet state failed: ' + response.status);
25
+ const body = (await response.json());
26
+ if (typeof body.pet?.id !== 'string')
27
+ throw new Error('pet state has no selected pet');
28
+ return body.pet.id;
29
+ }
20
30
  /** Bridges the 'pet' scope onto the card's staged form. */
21
31
  export class PetSettingsCardController {
22
32
  form;
@@ -27,12 +37,16 @@ export class PetSettingsCardController {
27
37
  petChoices = [];
28
38
  petLabels = new Map();
29
39
  diagnostics = [];
40
+ selectedPetId;
41
+ stagedPetId;
42
+ savingPet = false;
43
+ petSaveFailed = false;
30
44
  loaded = false;
31
45
  attempts = 0;
32
46
  disposed = false;
33
47
  /** Pending deferred-load or retry timer; cancelled by dispose(). */
34
48
  pendingTimer;
35
- /** @param scope - the bound settings scope for the 'pet' namespace. */
49
+ /** @param scope - the bound configuration form for the 'pet' entry. */
36
50
  constructor(scope) {
37
51
  this.form = new CardForm(scope, [
38
52
  booleanField('enabled'),
@@ -55,6 +69,7 @@ export class PetSettingsCardController {
55
69
  return;
56
70
  void this.loadPets();
57
71
  void this.loadDiagnostics();
72
+ void this.loadSelectedPet();
58
73
  }, 0);
59
74
  }
60
75
  /** Fetch registry diagnostics once (soft-fail: an empty list on error). */
@@ -97,9 +112,69 @@ export class PetSettingsCardController {
97
112
  }
98
113
  }
99
114
  }
115
+ async loadSelectedPet() {
116
+ try {
117
+ const petId = await fetchSelectedPetId();
118
+ if (this.disposed)
119
+ return;
120
+ this.selectedPetId = petId;
121
+ this.store.set(this.projection());
122
+ }
123
+ catch {
124
+ // The Host form remains the authority when it is available. An absent
125
+ // pet API leaves the fallback unavailable rather than inventing state.
126
+ }
127
+ }
128
+ fallback() {
129
+ const shell = this.form.shell();
130
+ return shell.available && !shell.exposed && this.selectedPetId !== undefined;
131
+ }
132
+ async savePetSelection() {
133
+ const petId = this.stagedPetId;
134
+ if (petId === undefined || this.savingPet || !this.petChoices.includes(petId))
135
+ return;
136
+ this.savingPet = true;
137
+ this.petSaveFailed = false;
138
+ this.store.set(this.projection());
139
+ try {
140
+ const response = await fetch('/api/pet/set-pet', {
141
+ method: 'POST',
142
+ headers: { 'content-type': 'application/json' },
143
+ body: JSON.stringify({ petId }),
144
+ });
145
+ const result = (await response.json());
146
+ if (!response.ok || result.ok !== true || result.petId !== petId || await fetchSelectedPetId() !== petId) {
147
+ throw new Error('pet selection was not persisted');
148
+ }
149
+ this.selectedPetId = petId;
150
+ if (this.stagedPetId === petId)
151
+ this.stagedPetId = undefined;
152
+ }
153
+ catch {
154
+ this.petSaveFailed = true;
155
+ }
156
+ finally {
157
+ this.savingPet = false;
158
+ if (!this.disposed)
159
+ this.store.set(this.projection());
160
+ }
161
+ }
100
162
  projection() {
163
+ const fallback = this.fallback();
164
+ const shell = this.form.shell();
165
+ const configuredPet = this.form.field('petId');
101
166
  return {
102
- ...this.form.shell(),
167
+ ...shell,
168
+ ...(fallback ? {
169
+ exposed: true,
170
+ writable: true,
171
+ dirty: this.stagedPetId !== undefined && this.stagedPetId !== this.selectedPetId,
172
+ invalid: this.stagedPetId !== undefined && !this.petChoices.includes(this.stagedPetId),
173
+ saving: this.savingPet,
174
+ failed: this.petSaveFailed,
175
+ failedReason: undefined,
176
+ } : {}),
177
+ petSelectionFallback: fallback,
103
178
  enabled: this.form.field('enabled'),
104
179
  decorationEnabled: this.form.field('decorationEnabled'),
105
180
  visible: this.form.field('visible'),
@@ -107,7 +182,11 @@ export class PetSettingsCardController {
107
182
  right: this.form.field('right'),
108
183
  bottom: this.form.field('bottom'),
109
184
  bubbleScale: this.form.field('bubbleScale'),
110
- petId: this.form.field('petId'),
185
+ petId: fallback
186
+ ? { text: this.stagedPetId ?? this.selectedPetId ?? '', overridden: false, invalid: this.stagedPetId !== undefined && !this.petChoices.includes(this.stagedPetId) }
187
+ : configuredPet.text === '' && this.selectedPetId !== undefined
188
+ ? { ...configuredPet, text: this.selectedPetId }
189
+ : configuredPet,
111
190
  petChoices: this.petChoices.map(id => ({ value: id, label: this.petLabels.get(id) ?? id })),
112
191
  petDiagnostics: this.diagnostics,
113
192
  };
@@ -117,7 +196,39 @@ export class PetSettingsCardController {
117
196
  * @returns the card's snapshot and its form actions.
118
197
  */
119
198
  inject() {
120
- return { hooks: { petSettingsCard: this.store }, ...this.form.actions() };
199
+ const actions = this.form.actions();
200
+ return {
201
+ hooks: { petSettingsCard: this.store },
202
+ edit: (field, value) => {
203
+ if (!this.fallback())
204
+ return actions.edit(field, value);
205
+ if (field !== 'petId')
206
+ return;
207
+ this.stagedPetId = value === '' ? undefined : value;
208
+ this.petSaveFailed = false;
209
+ this.store.set(this.projection());
210
+ },
211
+ resetField: (field) => {
212
+ if (!this.fallback())
213
+ return actions.resetField(field);
214
+ if (field !== 'petId')
215
+ return;
216
+ this.stagedPetId = undefined;
217
+ this.petSaveFailed = false;
218
+ this.store.set(this.projection());
219
+ },
220
+ save: () => { if (this.fallback())
221
+ void this.savePetSelection();
222
+ else
223
+ actions.save(); },
224
+ discard: () => {
225
+ if (!this.fallback())
226
+ return actions.discard();
227
+ this.stagedPetId = undefined;
228
+ this.petSaveFailed = false;
229
+ this.store.set(this.projection());
230
+ },
231
+ };
121
232
  }
122
233
  /**
123
234
  * Release the card's scope subscription, bound stores and pending load
@@ -149,7 +260,7 @@ export function PetSettingsCard(props) {
149
260
  invalidLabel: t('settings.invalidNumber'),
150
261
  disabled,
151
262
  };
152
- return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", state: state, onSave: props.save, onDiscard: props.discard, alwaysOpen: true, children: [_jsx(BooleanField, { id: "settings-pet-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), _jsx(BooleanField, { id: "settings-pet-decoration", label: t('settings.decoration'), hint: t('settings.decorationHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.decorationEnabled, onEdit: (text) => { props.edit('decorationEnabled', text); }, onReset: () => { props.resetField('decorationEnabled'); } }), _jsx(ChoiceField, { id: "settings-pet-pet", label: t('settings.pet'), hint: t('settings.petHint'), inheritLabel: t('settings.inherit'), ...fieldProps, ...state.petId, choices: state.petChoices, onEdit: (text) => { props.edit('petId', text); }, onReset: () => { props.resetField('petId'); } }), state.petDiagnostics.length === 0 ? null : (_jsxs("li", { className: sectionCss.diagnostics, "data-dsh-part": "diagnostics", children: [_jsx("span", { className: sectionCss.diagnosticsTitle, children: t('settings.diagnosticsTitle') }), _jsx("ul", { children: state.petDiagnostics.map((diagnostic, index) => (_jsx("li", { "data-level": diagnostic.level, children: diagnostic.message }, index))) })] })), _jsx(BooleanField, { id: "settings-pet-visible", label: t('settings.visible'), hint: t('settings.visibleHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.visible, onEdit: (text) => { props.edit('visible', text); }, onReset: () => { props.resetField('visible'); } }), _jsx(ValueField, { id: "settings-pet-size", label: t('settings.size'), hint: t('settings.sizeHint'), numeric: true, ...fieldProps, ...state.size, onEdit: (text) => { props.edit('size', text); }, onReset: () => { props.resetField('size'); } }), _jsx(ValueField, { id: "settings-pet-right", label: t('settings.right'), hint: t('settings.rightHint'), numeric: true, ...fieldProps, ...state.right, onEdit: (text) => { props.edit('right', text); }, onReset: () => { props.resetField('right'); } }), _jsx(ValueField, { id: "settings-pet-bottom", label: t('settings.bottom'), hint: t('settings.bottomHint'), numeric: true, ...fieldProps, ...state.bottom, onEdit: (text) => { props.edit('bottom', text); }, onReset: () => { props.resetField('bottom'); } }), _jsx(ValueField, { id: "settings-pet-bubble-scale", label: t('settings.bubbleScale'), hint: t('settings.bubbleScaleHint'), numeric: true, ...fieldProps, ...state.bubbleScale, onEdit: (text) => { props.edit('bubbleScale', text); }, onReset: () => { props.resetField('bubbleScale'); } })] }));
263
+ return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", descriptionNode: state.petSelectionFallback ? t('settings.petHint') : undefined, state: state, onSave: props.save, onDiscard: props.discard, alwaysOpen: true, children: [state.petSelectionFallback ? null : _jsx(BooleanField, { id: "settings-pet-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), state.petSelectionFallback ? null : _jsx(BooleanField, { id: "settings-pet-decoration", label: t('settings.decoration'), hint: t('settings.decorationHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.decorationEnabled, onEdit: (text) => { props.edit('decorationEnabled', text); }, onReset: () => { props.resetField('decorationEnabled'); } }), _jsx(ChoiceField, { id: "settings-pet-pet", label: t('settings.pet'), hint: t('settings.petHint'), inheritLabel: t('settings.inherit'), ...fieldProps, ...state.petId, choices: state.petChoices, onEdit: (text) => { props.edit('petId', text); }, onReset: () => { props.resetField('petId'); } }), state.petDiagnostics.length === 0 ? null : (_jsxs("li", { className: sectionCss.diagnostics, "data-dsh-part": "diagnostics", children: [_jsx("span", { className: sectionCss.diagnosticsTitle, children: t('settings.diagnosticsTitle') }), _jsx("ul", { children: state.petDiagnostics.map((diagnostic, index) => (_jsx("li", { "data-level": diagnostic.level, children: diagnostic.message }, index))) })] })), state.petSelectionFallback ? null : _jsx(BooleanField, { id: "settings-pet-visible", label: t('settings.visible'), hint: t('settings.visibleHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.visible, onEdit: (text) => { props.edit('visible', text); }, onReset: () => { props.resetField('visible'); } }), state.petSelectionFallback ? null : _jsx(ValueField, { id: "settings-pet-size", label: t('settings.size'), hint: t('settings.sizeHint'), numeric: true, ...fieldProps, ...state.size, onEdit: (text) => { props.edit('size', text); }, onReset: () => { props.resetField('size'); } }), state.petSelectionFallback ? null : _jsx(ValueField, { id: "settings-pet-right", label: t('settings.right'), hint: t('settings.rightHint'), numeric: true, ...fieldProps, ...state.right, onEdit: (text) => { props.edit('right', text); }, onReset: () => { props.resetField('right'); } }), state.petSelectionFallback ? null : _jsx(ValueField, { id: "settings-pet-bottom", label: t('settings.bottom'), hint: t('settings.bottomHint'), numeric: true, ...fieldProps, ...state.bottom, onEdit: (text) => { props.edit('bottom', text); }, onReset: () => { props.resetField('bottom'); } }), state.petSelectionFallback ? null : _jsx(ValueField, { id: "settings-pet-bubble-scale", label: t('settings.bubbleScale'), hint: t('settings.bubbleScaleHint'), numeric: true, ...fieldProps, ...state.bubbleScale, onEdit: (text) => { props.edit('bubbleScale', text); }, onReset: () => { props.resetField('bubbleScale'); } })] }));
153
264
  }
154
265
  /** Render the pet settings card as a first-level settings page. */
155
266
  export function PetSettingsSection(props) {
@@ -13,6 +13,7 @@ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
13
13
  import { type PetDisplayConfig } from '../persist.ts';
14
14
  import type { PetStateView } from '../service.ts';
15
15
  import type { PetDefinition } from '../registry.ts';
16
+ import type { GameplayBus } from './gameplay-hud.ts';
16
17
  import type { PetFeedback } from './pet-store.ts';
17
18
  import { NS } from './locales.ts';
18
19
  /** Props injected by the plugin apply body (store actions + locale). */
@@ -68,6 +69,11 @@ export interface PetSpriteProps {
68
69
  onGameplayMenu?: () => void;
69
70
  /** Disable the drag gesture (gameplay work mode blocks dragging). */
70
71
  dragDisabled?: boolean;
72
+ /**
73
+ * Per-pet coordination bus. The chrome registers `walk` here so the gameplay
74
+ * HUD can roam the pet (the same two-way shape the HUD's `tap` uses).
75
+ */
76
+ bus?: GameplayBus;
71
77
  /**
72
78
  * DOM node the floating chrome portals into. Defaults to document.body
73
79
  * (the legacy behavior); the plugin apply passes its owning root (the
@@ -1 +1 @@
1
- {"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAkE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9C,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4DAA4D;IAC5D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,CAAA;IACf;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAkJD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CAgmB5D"}
1
+ {"version":3,"file":"PetSprite.d.ts","sourceRoot":"","sources":["../../../src/client/PetSprite.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAkE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,UAAU,EAAE,aAAa,CAAA;IACzB,qDAAqD;IACrD,OAAO,EAAE,gBAAgB,CAAA;IACzB,sCAAsC;IACtC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9C,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4DAA4D;IAC5D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,2DAA2D;IAC3D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,CAAA;IACf;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,+CAA+C;IAC/C,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;CAC1B;AAkJD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CAyrB5D"}
@@ -371,6 +371,7 @@ export function PetSprite(props) {
371
371
  const onPointerDown = (e) => {
372
372
  if (props.dragDisabled === true)
373
373
  return;
374
+ endWalk(false);
374
375
  e.preventDefault();
375
376
  e.target.setPointerCapture?.(e.pointerId);
376
377
  const current = dragPos ?? { right: display.right, bottom: display.bottom };
@@ -405,6 +406,99 @@ export function PetSprite(props) {
405
406
  const pos = dragPos ?? { right: display.right, bottom: display.bottom };
406
407
  const spriteWidth = Math.round(cell.width * spriteScale);
407
408
  const spriteHeight = Math.round(cell.height * spriteScale);
409
+ // --- roaming ---------------------------------------------------------
410
+ // The gameplay HUD rolls when the pet may wander; this side owns the motion
411
+ // (clamped to the viewport), the walk art's facing and the persisted resting
412
+ // spot -- the walk ends on the same write a drag ends with. The walk art
413
+ // faces left, so a rightward walk mirrors the sprite (a vertical walk keeps
414
+ // the side view); every other track stays unmirrored.
415
+ const [facingRight, setFacingRight] = useState(false);
416
+ const walkRafRef = useRef(0);
417
+ const walkTargetRef = useRef(null);
418
+ const dragPosRef = useRef(dragPos);
419
+ dragPosRef.current = dragPos;
420
+ /** Stop an active walk; `persist` lands the pet on the spot it reached. */
421
+ const endWalk = (persist) => {
422
+ if (walkRafRef.current === 0)
423
+ return;
424
+ window.cancelAnimationFrame(walkRafRef.current);
425
+ walkRafRef.current = 0;
426
+ setFacingRight(false);
427
+ const settled = walkTargetRef.current;
428
+ walkTargetRef.current = null;
429
+ if (persist && settled !== null)
430
+ props.onDragEnd(settled.right, settled.bottom);
431
+ };
432
+ useEffect(() => {
433
+ const bus = props.bus;
434
+ if (bus === undefined)
435
+ return undefined;
436
+ bus.walk = (direction, distance, speed) => {
437
+ if (dragRef.current !== null || walkRafRef.current !== 0)
438
+ return 0;
439
+ const current = dragPosRef.current ?? { right: display.right, bottom: display.bottom };
440
+ // Keep the whole sprite on screen with an 8px breathing margin. `right`
441
+ // and `bottom` are CSS offsets: right grows leftwards, bottom upwards.
442
+ const margin = 8;
443
+ const maxRight = Math.max(margin, window.innerWidth - spriteWidth - margin);
444
+ const maxBottom = Math.max(margin, window.innerHeight - spriteHeight - margin);
445
+ const wanted = { ...current };
446
+ if (direction === 'left')
447
+ wanted.right = current.right + distance;
448
+ else if (direction === 'right')
449
+ wanted.right = current.right - distance;
450
+ else if (direction === 'up')
451
+ wanted.bottom = current.bottom + distance;
452
+ else
453
+ wanted.bottom = current.bottom - distance;
454
+ const target = {
455
+ right: Math.max(margin, clampOffset(wanted.right, maxRight)),
456
+ bottom: Math.max(margin, clampOffset(wanted.bottom, maxBottom)),
457
+ };
458
+ const travelled = direction === 'left' ? target.right - current.right
459
+ : direction === 'right' ? current.right - target.right
460
+ : direction === 'up' ? target.bottom - current.bottom
461
+ : current.bottom - target.bottom;
462
+ if (travelled < 1)
463
+ return 0;
464
+ const duration = Math.max(150, (travelled / Math.max(1, speed)) * 1000);
465
+ const startedAt = performance.now();
466
+ // The crawl art faces left, so only a rightward walk mirrors it; a
467
+ // vertical walk keeps the side view (there is no front/back art).
468
+ setFacingRight(direction === 'right');
469
+ walkTargetRef.current = current;
470
+ const step = (now) => {
471
+ const t = Math.min(1, (now - startedAt) / duration);
472
+ const next = {
473
+ right: current.right + (target.right - current.right) * t,
474
+ bottom: current.bottom + (target.bottom - current.bottom) * t,
475
+ };
476
+ walkTargetRef.current = next;
477
+ setDragPos(next);
478
+ if (t < 1) {
479
+ walkRafRef.current = window.requestAnimationFrame(step);
480
+ return;
481
+ }
482
+ walkRafRef.current = 0;
483
+ walkTargetRef.current = null;
484
+ setFacingRight(false);
485
+ props.onDragEnd(next.right, next.bottom);
486
+ };
487
+ walkRafRef.current = window.requestAnimationFrame(step);
488
+ return travelled;
489
+ };
490
+ return () => {
491
+ bus.walk = undefined;
492
+ if (walkRafRef.current !== 0) {
493
+ window.cancelAnimationFrame(walkRafRef.current);
494
+ walkRafRef.current = 0;
495
+ }
496
+ // A cancelled walk must not leave the sprite mirrored.
497
+ setFacingRight(false);
498
+ walkTargetRef.current = null;
499
+ };
500
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- one registration per sprite
501
+ }, [props.bus, definition.id, display.right, display.bottom, spriteWidth]);
408
502
  // Bubble typography follows the sprite's own scale (#1549), bounded so a
409
503
  // shrunk pet never carries unreadably small text.
410
504
  const bubbleScale = bubbleScaleFor(display);
@@ -508,6 +602,7 @@ export function PetSprite(props) {
508
602
  }
509
603
  : {}),
510
604
  cursor: dragRef.current === null ? 'grab' : 'grabbing',
605
+ ...(facingRight ? { transform: 'scaleX(-1)' } : {}),
511
606
  }, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onClick: (e) => {
512
607
  // A pointer sequence that moved (dragged) still fires a trailing
513
608
  // click; skip the pet when that happened.
@@ -47,6 +47,10 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
47
47
  * edits, so the footer would sit there permanently disabled.
48
48
  */
49
49
  hideFooter?: boolean;
50
+ /** Render children even when the settings namespace is not exposed by the host. */
51
+ renderChildrenWhenNotExposed?: boolean;
52
+ /** Hide the 'not exposed' warning banner when the settings namespace is not exposed. */
53
+ hideNotExposedNotice?: boolean;
50
54
  /** The plugin's controls. */
51
55
  children: ReactNode;
52
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
@@ -46,9 +46,10 @@ export function PluginSettingsCard(props) {
46
46
  // official settings allowlist omits third-party namespaces): show a card
47
47
  // that explains the gap instead of vanishing, so a missing card never
48
48
  // reads as a missing plugin.
49
- if (!state.exposed) {
49
+ if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {
50
+ const showNotice = props.hideNotExposedNotice !== true;
50
51
  return (_jsxs("li", { className: cardClass, children: [header, expanded
51
- ? (_jsx("div", { className: css.body, children: _jsx("p", { className: css.notExposed, role: "status", children: props.t('settings.notExposed') }) }))
52
+ ? (_jsx("div", { className: css.body, children: showNotice ? _jsx("p", { className: css.notExposed, role: "status", children: props.t('settings.notExposed') }) : null }))
52
53
  : null] }));
53
54
  }
54
55
  return (_jsxs("li", { className: cardClass, children: [header, expanded
@@ -12,13 +12,14 @@ import { type ReactElement } from 'react';
12
12
  import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
13
13
  import type { PetDefinition } from '../registry.ts';
14
14
  import type { PetGameplayVerbResult } from '../service.ts';
15
+ import { type PetRoamDirection } from '../gameplay.ts';
15
16
  import type { PetStoreInstance } from './pet-store.ts';
16
17
  import type { DragStream } from './drag-stream.ts';
17
18
  import type { NS } from './locales.ts';
18
19
  /** The gameplay verb API the plugin apply body injects (host-authoritative). */
19
20
  export interface GameplayApi {
20
21
  touch: (zone?: string) => Promise<PetGameplayVerbResult>;
21
- setMode: (mode: 'work' | 'sleep' | null) => Promise<PetGameplayVerbResult>;
22
+ setMode: (mode: string | null) => Promise<PetGameplayVerbResult>;
22
23
  workTick: () => Promise<PetGameplayVerbResult>;
23
24
  buy: (item: string) => Promise<PetGameplayVerbResult>;
24
25
  /**
@@ -54,6 +55,14 @@ export interface GameplayBus {
54
55
  * while a boolean pins the state (same chrome -> HUD direction as tap).
55
56
  */
56
57
  openCard?: (open?: boolean) => void;
58
+ /**
59
+ * Walk the sprite in `direction` by `distance` px at `speed` px/s, clamped
60
+ * to the viewport, and persist the resting spot like a drag. Returns the
61
+ * distance actually travelled (0 when it cannot move), so the caller can
62
+ * hold the walk art for exactly that long. Registered by the chrome
63
+ * (PetSprite); absent while the sprite is unmounted.
64
+ */
65
+ walk?: (direction: PetRoamDirection, distance: number, speed: number) => number;
57
66
  }
58
67
  /** The gameplay overlay for one frames2d pet that declares 'gameplay'. */
59
68
  export declare function GameplayHud(props: {
@@ -1 +1 @@
1
- {"version":3,"file":"gameplay-hud.d.ts","sourceRoot":"","sources":["../../../src/client/gameplay-hud.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC7G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,gBAAgB,CAAA;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGtC,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACxD,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC1E,QAAQ,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC9C,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACrD;;;OAGG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChF;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,gFAAgF;IAChF,YAAY,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAYD,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,UAAU,EAAE,aAAa,CAAA;IACzB,KAAK,EAAE,gBAAgB,CAAA;IACvB,GAAG,EAAE,WAAW,CAAA;IAChB,GAAG,EAAE,WAAW,CAAA;IAChB,IAAI,EAAE,UAAU,CAAA;IAChB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;CAC/B,GAAG,YAAY,GAAG,IAAI,CAodtB"}
1
+ {"version":3,"file":"gameplay-hud.d.ts","sourceRoot":"","sources":["../../../src/client/gameplay-hud.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AAC7G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,gBAAgB,CAAA;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAgE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACpH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGtC,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACxD,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAChE,QAAQ,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC9C,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACrD;;;OAGG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChF;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,gFAAgF;IAChF,YAAY,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACnC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CAChF;AAYD,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,UAAU,EAAE,aAAa,CAAA;IACzB,KAAK,EAAE,gBAAgB,CAAA;IACvB,GAAG,EAAE,WAAW,CAAA;IAChB,GAAG,EAAE,WAAW,CAAA;IAChB,IAAI,EAAE,UAAU,CAAA;IAChB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;CAC/B,GAAG,YAAY,GAAG,IAAI,CA+jBtB"}