@linxin666/dsh-pet 0.3.21 → 0.3.23
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.
- package/README.i18n.yaml +2 -2
- package/README.md +1 -0
- package/README.zh.md +1 -0
- package/lib/client.js +73 -10
- package/lib/client.js.map +1 -1
- package/lib/index.js +10 -3
- package/lib/types/client/PetDockEntry.js +1 -1
- package/lib/types/client/PetSettingsCard.d.ts +4 -0
- package/lib/types/client/PetSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PetSettingsCard.js +3 -1
- package/lib/types/client/PetSprite.d.ts +1 -1
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +45 -8
- package/lib/types/client/locales.d.ts +4 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +4 -0
- package/lib/types/index.d.ts +2 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -1
- package/lib/types/persist.d.ts +32 -0
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +37 -0
- package/lib/types/service.d.ts +3 -1
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +4 -2
- package/package.json +1 -1
- package/src/client/PetDockEntry.test.tsx +1 -1
- package/src/client/PetDockEntry.tsx +1 -1
- package/src/client/PetSettingsCard.tsx +16 -0
- package/src/client/PetSprite.test.tsx +63 -1
- package/src/client/PetSprite.tsx +45 -8
- package/src/client/gameplay-hud.test.tsx +1 -1
- package/src/client/locales.ts +4 -0
- package/src/client/pet-css.test.ts +14 -0
- package/src/client/pet-store.test.ts +1 -1
- package/src/client/pet.module.css +7 -4
- package/src/index.ts +2 -1
- package/src/persist.test.ts +53 -1
- package/src/persist.ts +46 -0
- package/src/service.ts +7 -1
package/lib/index.js
CHANGED
|
@@ -1391,10 +1391,13 @@ const defaultDisplayConfig = {
|
|
|
1391
1391
|
visible: true,
|
|
1392
1392
|
size: 160,
|
|
1393
1393
|
right: 24,
|
|
1394
|
-
bottom: 120
|
|
1394
|
+
bottom: 120,
|
|
1395
|
+
bubbleScale: 1
|
|
1395
1396
|
};
|
|
1396
1397
|
const DISPLAY_SIZE_MAX = 1024;
|
|
1397
1398
|
const DISPLAY_INSET_MAX = 1e4;
|
|
1399
|
+
/** Bubble typography bounds (issue #1549). */
|
|
1400
|
+
const BUBBLE_SCALE_MIN = .5;
|
|
1398
1401
|
/** Name constraints. */
|
|
1399
1402
|
const PET_NAME_MAX_LENGTH = 20;
|
|
1400
1403
|
function emptyPersist() {
|
|
@@ -1508,7 +1511,8 @@ function loadPetPersist(dir = petHomeDir()) {
|
|
|
1508
1511
|
visible: typeof rawDisplay.visible === "boolean" ? rawDisplay.visible : base.display.visible,
|
|
1509
1512
|
size: Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(32, finiteNum(rawDisplay.size, base.display.size)))),
|
|
1510
1513
|
right: Math.round(clamp(finiteNum(rawDisplay.right, base.display.right), DISPLAY_INSET_MAX)),
|
|
1511
|
-
bottom: Math.round(clamp(finiteNum(rawDisplay.bottom, base.display.bottom), DISPLAY_INSET_MAX))
|
|
1514
|
+
bottom: Math.round(clamp(finiteNum(rawDisplay.bottom, base.display.bottom), DISPLAY_INSET_MAX)),
|
|
1515
|
+
bubbleScale: Math.min(2, Math.max(BUBBLE_SCALE_MIN, finiteNum(rawDisplay.bubbleScale, base.display.bubbleScale)))
|
|
1512
1516
|
};
|
|
1513
1517
|
const petId = typeof parsed.petId === "string" && parsed.petId.trim() !== "" ? parsed.petId.trim() : base.petId;
|
|
1514
1518
|
const names = loadPetNames(parsed);
|
|
@@ -4882,7 +4886,7 @@ var PetService = class extends Service {
|
|
|
4882
4886
|
skin
|
|
4883
4887
|
};
|
|
4884
4888
|
}
|
|
4885
|
-
/** RPC: update display config (size / position).
|
|
4889
|
+
/** RPC: update display config (size / position / bubble scale). Pixel values are clamped to whole pixels. */
|
|
4886
4890
|
async setConfig(patch) {
|
|
4887
4891
|
const next = {
|
|
4888
4892
|
...this.ledger.snapshot.display,
|
|
@@ -4891,6 +4895,7 @@ var PetService = class extends Service {
|
|
|
4891
4895
|
next.size = Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(32, next.size)));
|
|
4892
4896
|
next.right = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, next.right)));
|
|
4893
4897
|
next.bottom = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, next.bottom)));
|
|
4898
|
+
next.bubbleScale = Math.min(2, Math.max(BUBBLE_SCALE_MIN, next.bubbleScale));
|
|
4894
4899
|
this.ledger.setDisplay(next);
|
|
4895
4900
|
this.flush();
|
|
4896
4901
|
this.syncSettingsFromPet();
|
|
@@ -4935,6 +4940,7 @@ var PetService = class extends Service {
|
|
|
4935
4940
|
next.size = Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(32, section.size)));
|
|
4936
4941
|
next.right = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.right)));
|
|
4937
4942
|
next.bottom = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.bottom)));
|
|
4943
|
+
next.bubbleScale = Math.min(2, Math.max(BUBBLE_SCALE_MIN, section.bubbleScale ?? next.bubbleScale));
|
|
4938
4944
|
this.ledger.setDisplay(next);
|
|
4939
4945
|
this.flush();
|
|
4940
4946
|
}
|
|
@@ -5808,6 +5814,7 @@ function makePetSettingsSchema(fallbackPetId) {
|
|
|
5808
5814
|
size: z.number().step(1).min(32).max(DISPLAY_SIZE_MAX).default(160),
|
|
5809
5815
|
right: z.number().step(1).min(0).max(DISPLAY_INSET_MAX).default(24),
|
|
5810
5816
|
bottom: z.number().step(1).min(0).max(DISPLAY_INSET_MAX).default(20),
|
|
5817
|
+
bubbleScale: z.number().step(.05).min(BUBBLE_SCALE_MIN).max(2).default(1),
|
|
5811
5818
|
petId: z.string().default(fallbackPetId),
|
|
5812
5819
|
enabled: z.boolean().default(true),
|
|
5813
5820
|
decorationEnabled: z.boolean().default(true)
|
|
@@ -18,7 +18,7 @@ import { PetRendererSwitch } from "./renderers/PetRendererSwitch.js";
|
|
|
18
18
|
import { createDragStream } from "./drag-stream.js";
|
|
19
19
|
import { GameplayHud } from "./gameplay-hud.js";
|
|
20
20
|
import styles from './pet.module.css';
|
|
21
|
-
const DEFAULT_DISPLAY = { visible: true, size: 160, right: 24, bottom: 20 };
|
|
21
|
+
const DEFAULT_DISPLAY = { visible: true, size: 160, right: 24, bottom: 20, bubbleScale: 1 };
|
|
22
22
|
/**
|
|
23
23
|
* Dock entry: while the pet is visible, mount the floating PetSprite (it
|
|
24
24
|
* portals itself onto document.body); while hidden, render the summon
|
|
@@ -23,6 +23,8 @@ export interface PetSettings {
|
|
|
23
23
|
right?: number;
|
|
24
24
|
/** Vertical inset from the viewport bottom edge, px. */
|
|
25
25
|
bottom?: number;
|
|
26
|
+
/** Bubble typography multiplier on the automatic size following (#1549). */
|
|
27
|
+
bubbleScale?: number;
|
|
26
28
|
/** Selected pet id (a registry entry). */
|
|
27
29
|
petId?: string;
|
|
28
30
|
/** Status-decoration master switch (pet-center M5, #567). */
|
|
@@ -40,6 +42,8 @@ export interface PetSettingsCardState extends CardShell {
|
|
|
40
42
|
right: CardFieldState;
|
|
41
43
|
/** Bottom inset. */
|
|
42
44
|
bottom: CardFieldState;
|
|
45
|
+
/** Bubble typography multiplier. */
|
|
46
|
+
bubbleScale: CardFieldState;
|
|
43
47
|
/** Selected pet. */
|
|
44
48
|
petId: CardFieldState;
|
|
45
49
|
/** Status-decoration master switch. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAA;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAIlE,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAG1J,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,4BAA4B;IAC5B,OAAO,EAAE,cAAc,CAAA;IACvB,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,iBAAiB;IACjB,IAAI,EAAE,cAAc,CAAA;IACpB,mBAAmB;IACnB,KAAK,EAAE,cAAc,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,oBAAoB;IACpB,KAAK,EAAE,cAAc,CAAA;IACrB,uCAAuC;IACvC,iBAAiB,EAAE,cAAc,CAAA;IACjC,wEAAwE;IACxE,UAAU,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACvD,+EAA+E;IAC/E,cAAc,EAAE,SAAS,iBAAiB,EAAE,CAAA;CAC7C;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,KAAK,EAAE;QACL,iEAAiE;QACjE,eAAe,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;KACrD,CAAA;CACF;AAQD,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAiBD,2DAA2D;AAC3D,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAI3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,QAAQ,CAAQ;IACxB,oEAAoE;IACpE,OAAO,CAAC,YAAY,CAAoB;IAExC,uEAAuE;gBAC3D,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"PetSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PetSettingsCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,7 @@ export class PetSettingsCardController {
|
|
|
41
41
|
numberField('size'),
|
|
42
42
|
numberField('right'),
|
|
43
43
|
numberField('bottom'),
|
|
44
|
+
numberField('bubbleScale'),
|
|
44
45
|
choiceField('petId', this.petChoices),
|
|
45
46
|
]);
|
|
46
47
|
this.store = this.form.bind(() => this.projection());
|
|
@@ -105,6 +106,7 @@ export class PetSettingsCardController {
|
|
|
105
106
|
size: this.form.field('size'),
|
|
106
107
|
right: this.form.field('right'),
|
|
107
108
|
bottom: this.form.field('bottom'),
|
|
109
|
+
bubbleScale: this.form.field('bubbleScale'),
|
|
108
110
|
petId: this.form.field('petId'),
|
|
109
111
|
petChoices: this.petChoices.map(id => ({ value: id, label: this.petLabels.get(id) ?? id })),
|
|
110
112
|
petDiagnostics: this.diagnostics,
|
|
@@ -147,7 +149,7 @@ export function PetSettingsCard(props) {
|
|
|
147
149
|
invalidLabel: t('settings.invalidNumber'),
|
|
148
150
|
disabled,
|
|
149
151
|
};
|
|
150
|
-
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'); } })] }));
|
|
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'); } })] }));
|
|
151
153
|
}
|
|
152
154
|
/** Render the pet settings card as a first-level settings page. */
|
|
153
155
|
export function PetSettingsSection(props) {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ReactNode, ReactPortal } from 'react';
|
|
12
12
|
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
13
|
-
import type
|
|
13
|
+
import { type PetDisplayConfig } from '../persist.ts';
|
|
14
14
|
import type { PetStateView } from '../service.ts';
|
|
15
15
|
import type { PetDefinition } from '../registry.ts';
|
|
16
16
|
import type { PetFeedback } from './pet-store.ts';
|
|
@@ -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,KAAK,
|
|
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"}
|
|
@@ -12,6 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
12
12
|
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import clsx from 'clsx';
|
|
15
|
+
import { bubbleScaleFor } from "../persist.js";
|
|
15
16
|
import { announcementFresh } from "../announce.js";
|
|
16
17
|
import { framePosition, rowOfTrack, trimTrack } from "./spritesheet.js";
|
|
17
18
|
import { createSequenceTimeline } from "./sequences.js";
|
|
@@ -67,7 +68,7 @@ function StatusOrnament(props) {
|
|
|
67
68
|
const delta = now - last;
|
|
68
69
|
last = now;
|
|
69
70
|
elapsed += delta;
|
|
70
|
-
|
|
71
|
+
let duration = decoration.durations[index] ?? 120;
|
|
71
72
|
// The segment's frame rate (duration ms, typically 90-160) is far
|
|
72
73
|
// below the rAF cadence, so a 60fps loop would spend ~90% of its
|
|
73
74
|
// ticks doing nothing. Schedule by the remaining time to the next
|
|
@@ -81,6 +82,10 @@ function StatusOrnament(props) {
|
|
|
81
82
|
index += 1;
|
|
82
83
|
else if (decoration.loop)
|
|
83
84
|
index = segment.from;
|
|
85
|
+
// Durations are per frame: a catch-up that crosses frames must
|
|
86
|
+
// subtract and schedule with the frame it lands on, not the one
|
|
87
|
+
// the tick started from.
|
|
88
|
+
duration = decoration.durations[index] ?? 120;
|
|
84
89
|
} while (elapsed >= duration);
|
|
85
90
|
// Only advance the background when the frame actually changes.
|
|
86
91
|
el.style.backgroundPosition = position(index);
|
|
@@ -201,16 +206,39 @@ export function PetSprite(props) {
|
|
|
201
206
|
useEffect(() => {
|
|
202
207
|
if (props.visual !== undefined)
|
|
203
208
|
return;
|
|
209
|
+
setImageReady(false);
|
|
204
210
|
let cancelled = false;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
let retryTimer;
|
|
212
|
+
let attempt = 0;
|
|
213
|
+
const maxAttempts = 3;
|
|
214
|
+
let activeImg = null;
|
|
215
|
+
const loadAtlas = () => {
|
|
216
|
+
const img = new Image();
|
|
217
|
+
activeImg = img;
|
|
218
|
+
img.onload = () => {
|
|
219
|
+
if (!cancelled)
|
|
220
|
+
setImageReady(true);
|
|
221
|
+
};
|
|
222
|
+
img.onerror = () => {
|
|
223
|
+
if (cancelled)
|
|
224
|
+
return;
|
|
225
|
+
if (attempt < maxAttempts) {
|
|
226
|
+
attempt += 1;
|
|
227
|
+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 8000);
|
|
228
|
+
retryTimer = setTimeout(loadAtlas, delay);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
img.src = definition.atlasUrl;
|
|
209
232
|
};
|
|
210
|
-
|
|
233
|
+
loadAtlas();
|
|
211
234
|
return () => {
|
|
212
235
|
cancelled = true;
|
|
213
|
-
|
|
236
|
+
if (retryTimer !== undefined)
|
|
237
|
+
clearTimeout(retryTimer);
|
|
238
|
+
if (activeImg !== null) {
|
|
239
|
+
activeImg.onload = null;
|
|
240
|
+
activeImg.onerror = null;
|
|
241
|
+
}
|
|
214
242
|
};
|
|
215
243
|
}, [definition.atlasUrl, props.visual]);
|
|
216
244
|
// Frame loop: advance the current track and write background-position.
|
|
@@ -377,6 +405,9 @@ export function PetSprite(props) {
|
|
|
377
405
|
const pos = dragPos ?? { right: display.right, bottom: display.bottom };
|
|
378
406
|
const spriteWidth = Math.round(cell.width * spriteScale);
|
|
379
407
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
408
|
+
// Bubble typography follows the sprite's own scale (#1549), bounded so a
|
|
409
|
+
// shrunk pet never carries unreadably small text.
|
|
410
|
+
const bubbleScale = bubbleScaleFor(display);
|
|
380
411
|
// Concurrent sessions share one bubble slot: only the display session
|
|
381
412
|
// speaks by default, and the rest hide behind a '+N' badge until the stack
|
|
382
413
|
// is hovered/pinned open. The legacy single 'bubble' is the fallback when
|
|
@@ -436,7 +467,13 @@ export function PetSprite(props) {
|
|
|
436
467
|
window.addEventListener('resize', updatePanelPlacement);
|
|
437
468
|
return () => window.removeEventListener('resize', updatePanelPlacement);
|
|
438
469
|
}, [hovered, renaming, pos.right, pos.bottom, display.size, bubblePresent, sessionBubbles.length, stackOpen, feedback]);
|
|
439
|
-
const float = (_jsxs("div", { ref: floatRef, className: styles.float, style: {
|
|
470
|
+
const float = (_jsxs("div", { ref: floatRef, className: styles.float, style: {
|
|
471
|
+
right: pos.right,
|
|
472
|
+
bottom: pos.bottom,
|
|
473
|
+
zIndex: 2147483000,
|
|
474
|
+
// Read by .bubble / .bubbleStatus in pet.module.css.
|
|
475
|
+
...{ '--pet-bubble-scale': String(bubbleScale) },
|
|
476
|
+
}, onPointerEnter: () => {
|
|
440
477
|
clearHideTimer();
|
|
441
478
|
setHovered(true);
|
|
442
479
|
}, onPointerLeave: (e) => {
|
|
@@ -65,6 +65,8 @@ export declare const zh: {
|
|
|
65
65
|
readonly 'settings.visibleHint': "关闭后宠物隐藏,可从聊天输入区重新召唤。";
|
|
66
66
|
readonly 'settings.size': "大小(px)";
|
|
67
67
|
readonly 'settings.sizeHint': "精灵单元高度,范围 32–1024。";
|
|
68
|
+
readonly 'settings.bubbleScale': "气泡字号倍率";
|
|
69
|
+
readonly 'settings.bubbleScaleHint': "状态、碎碎念与用量气泡的字号会随宠物大小自动缩放;这一项是在此基础上再乘一个倍率(0.5–2,默认 1)。字号本身不小于 10px、不大于 24px。";
|
|
68
70
|
readonly 'settings.right': "距右侧(px)";
|
|
69
71
|
readonly 'settings.rightHint': "距视口右边缘的水平内缩距离。";
|
|
70
72
|
readonly 'settings.bottom': "距底部(px)";
|
|
@@ -146,6 +148,8 @@ export declare const en: {
|
|
|
146
148
|
readonly 'settings.visibleHint': "When off, the pet hides; summon it again from the input row.";
|
|
147
149
|
readonly 'settings.size': "Size (px)";
|
|
148
150
|
readonly 'settings.sizeHint': "Sprite cell height, 32–1024.";
|
|
151
|
+
readonly 'settings.bubbleScale': "Bubble text multiplier";
|
|
152
|
+
readonly 'settings.bubbleScaleHint': "Status, whisper, and usage bubbles scale with the pet automatically; this multiplies that result (0.5–2, default 1). The rendered text stays between 10px and 24px.";
|
|
149
153
|
readonly 'settings.right': "Right inset (px)";
|
|
150
154
|
readonly 'settings.rightHint': "Horizontal inset from the viewport right edge.";
|
|
151
155
|
readonly 'settings.bottom': "Bottom inset (px)";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mDAAmD;AACnD,eAAO,MAAM,EAAE,QAAQ,CAAA;AAEvB,oBAAoB;AACpB,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mDAAmD;AACnD,eAAO,MAAM,EAAE,QAAQ,CAAA;AAEvB,oBAAoB;AACpB,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFL,CAAA;AAEV,oBAAoB;AACpB,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFL,CAAA;AAEV,oCAAoC;AACpC,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAA;AAEpC,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,MAAM,CAAA;AAEpC;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGnD;AAED;;;;;;;GAOG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAQvE;AAED,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,uBAAuB;QACvB,GAAG,EAAE,MAAM,CAAA;KACZ;CACF"}
|
|
@@ -67,6 +67,8 @@ export const zh = {
|
|
|
67
67
|
'settings.visibleHint': '关闭后宠物隐藏,可从聊天输入区重新召唤。',
|
|
68
68
|
'settings.size': '大小(px)',
|
|
69
69
|
'settings.sizeHint': '精灵单元高度,范围 32–1024。',
|
|
70
|
+
'settings.bubbleScale': '气泡字号倍率',
|
|
71
|
+
'settings.bubbleScaleHint': '状态、碎碎念与用量气泡的字号会随宠物大小自动缩放;这一项是在此基础上再乘一个倍率(0.5–2,默认 1)。字号本身不小于 10px、不大于 24px。',
|
|
70
72
|
'settings.right': '距右侧(px)',
|
|
71
73
|
'settings.rightHint': '距视口右边缘的水平内缩距离。',
|
|
72
74
|
'settings.bottom': '距底部(px)',
|
|
@@ -150,6 +152,8 @@ export const en = {
|
|
|
150
152
|
'settings.visibleHint': 'When off, the pet hides; summon it again from the input row.',
|
|
151
153
|
'settings.size': 'Size (px)',
|
|
152
154
|
'settings.sizeHint': 'Sprite cell height, 32\u20131024.',
|
|
155
|
+
'settings.bubbleScale': 'Bubble text multiplier',
|
|
156
|
+
'settings.bubbleScaleHint': 'Status, whisper, and usage bubbles scale with the pet automatically; this multiplies that result (0.5\u20132, default 1). The rendered text stays between 10px and 24px.',
|
|
153
157
|
'settings.right': 'Right inset (px)',
|
|
154
158
|
'settings.rightHint': 'Horizontal inset from the viewport right edge.',
|
|
155
159
|
'settings.bottom': 'Bottom inset (px)',
|
package/lib/types/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export declare function makePetSettingsSchema(fallbackPetId: string): z<Schemast
|
|
|
45
45
|
size: z<number, number>;
|
|
46
46
|
right: z<number, number>;
|
|
47
47
|
bottom: z<number, number>;
|
|
48
|
+
bubbleScale: z<number, number>;
|
|
48
49
|
petId: z<string, string>;
|
|
49
50
|
enabled: z<boolean, boolean>;
|
|
50
51
|
decorationEnabled: z<boolean, boolean>;
|
|
@@ -53,6 +54,7 @@ export declare function makePetSettingsSchema(fallbackPetId: string): z<Schemast
|
|
|
53
54
|
size: z<number, number>;
|
|
54
55
|
right: z<number, number>;
|
|
55
56
|
bottom: z<number, number>;
|
|
57
|
+
bubbleScale: z<number, number>;
|
|
56
58
|
petId: z<string, string>;
|
|
57
59
|
enabled: z<boolean, boolean>;
|
|
58
60
|
decorationEnabled: z<boolean, boolean>;
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAG7C,OAAO,CAAC,MAAM,aAAa,CAAA;AAC3B,OAAO,EAAsC,KAAK,SAAS,EAA2B,MAAM,cAAc,CAAA;AAM1G,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,MAAM,GACP,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,GACN,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,UAAU,EACV,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,GACnB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,aAAa,EACb,QAAQ,EACR,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,gBAAgB,GACjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAA;AAEpB,sEAAsE;AACtE,eAAO,MAAM,IAAI,QAAQ,CAAA;AAEzB,+DAA+D;AAC/D,eAAO,MAAM,MAAM,UAAgB,CAAA;AAEnC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAG7C,OAAO,CAAC,MAAM,aAAa,CAAA;AAC3B,OAAO,EAAsC,KAAK,SAAS,EAA2B,MAAM,cAAc,CAAA;AAM1G,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,MAAM,GACP,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,GACN,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,UAAU,EACV,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,GACnB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,aAAa,EACb,QAAQ,EACR,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,gBAAgB,GACjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,GACjB,MAAM,aAAa,CAAA;AAEpB,sEAAsE;AACtE,eAAO,MAAM,IAAI,QAAQ,CAAA;AAEzB,+DAA+D;AAC/D,eAAO,MAAM,MAAM,UAAgB,CAAA;AAEnC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM;;;;;;;;;;;;;;;;;;IAW1D;AAED,0EAA0E;AAC1E,eAAO,MAAM,KAAK,kBAA6C,CAAA;AAE/D,iBAAS,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,SAAc,GAAG,IAAI,CAkF7D"}
|
package/lib/types/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import z from 'schemastery';
|
|
|
14
14
|
import { PetService, PET_SETTINGS_NAMESPACE } from "./service.js";
|
|
15
15
|
import { makePetRoutes } from "./routes.js";
|
|
16
16
|
import { loadPetRegistry, petPackageRoot } from "./registry.js";
|
|
17
|
-
import { DISPLAY_INSET_MAX, DISPLAY_SIZE_MAX, DISPLAY_SIZE_MIN } from "./persist.js";
|
|
17
|
+
import { BUBBLE_SCALE_MAX, BUBBLE_SCALE_MIN, DISPLAY_INSET_MAX, DISPLAY_SIZE_MAX, DISPLAY_SIZE_MIN } from "./persist.js";
|
|
18
18
|
import { mountOnce } from "./mount-once.js";
|
|
19
19
|
export { PetService, MAX_SESSION_BUBBLES } from "./service.js";
|
|
20
20
|
export { AFFINITY_MAX, AFFINITY_RANKS, applyInteraction, applyTurnReward, emptyAffinity, rankOf, } from "./affinity.js";
|
|
@@ -42,6 +42,7 @@ export function makePetSettingsSchema(fallbackPetId) {
|
|
|
42
42
|
size: z.number().step(1).min(DISPLAY_SIZE_MIN).max(DISPLAY_SIZE_MAX).default(160),
|
|
43
43
|
right: z.number().step(1).min(0).max(DISPLAY_INSET_MAX).default(24),
|
|
44
44
|
bottom: z.number().step(1).min(0).max(DISPLAY_INSET_MAX).default(20),
|
|
45
|
+
bubbleScale: z.number().step(0.05).min(BUBBLE_SCALE_MIN).max(BUBBLE_SCALE_MAX).default(1),
|
|
45
46
|
petId: z.string().default(fallbackPetId),
|
|
46
47
|
enabled: z.boolean().default(true),
|
|
47
48
|
decorationEnabled: z.boolean().default(true),
|
package/lib/types/persist.d.ts
CHANGED
|
@@ -18,12 +18,44 @@ export interface PetDisplayConfig {
|
|
|
18
18
|
right: number;
|
|
19
19
|
/** Vertical inset from the viewport bottom edge, px. */
|
|
20
20
|
bottom: number;
|
|
21
|
+
/**
|
|
22
|
+
* Multiplier on the bubble typography's automatic size following (#1549).
|
|
23
|
+
* The rendered bubble scale is `size / 160 * bubbleScale`, bounded by
|
|
24
|
+
* {@link BUBBLE_FONT_MIN_PX}..{@link BUBBLE_FONT_MAX_PX}, so 1 keeps the
|
|
25
|
+
* 12px baseline the stylesheet was drawn for at the default 160px pet.
|
|
26
|
+
*/
|
|
27
|
+
bubbleScale: number;
|
|
21
28
|
}
|
|
22
29
|
export declare const defaultDisplayConfig: PetDisplayConfig;
|
|
23
30
|
/** Display value bounds (shared by load-time validation and setConfig). */
|
|
24
31
|
export declare const DISPLAY_SIZE_MIN = 32;
|
|
25
32
|
export declare const DISPLAY_SIZE_MAX = 1024;
|
|
26
33
|
export declare const DISPLAY_INSET_MAX = 10000;
|
|
34
|
+
/** Bubble typography bounds (issue #1549). */
|
|
35
|
+
export declare const BUBBLE_SCALE_MIN = 0.5;
|
|
36
|
+
export declare const BUBBLE_SCALE_MAX = 2;
|
|
37
|
+
/** Pixel size the bubble stylesheet was drawn for, at the default pet size. */
|
|
38
|
+
export declare const BUBBLE_BASE_FONT_PX = 12;
|
|
39
|
+
/** Pet size that baseline matches; other sizes scale the bubble with them. */
|
|
40
|
+
export declare const BUBBLE_BASE_SIZE_PX = 160;
|
|
41
|
+
/** Readability floor and layout ceiling of the scaled bubble text. */
|
|
42
|
+
export declare const BUBBLE_FONT_MIN_PX = 10;
|
|
43
|
+
export declare const BUBBLE_FONT_MAX_PX = 24;
|
|
44
|
+
/**
|
|
45
|
+
* Bubble typography scale for one display config (issue #1549): the bubble
|
|
46
|
+
* follows the pet's own size so a shrunk pet does not carry a full-size
|
|
47
|
+
* bubble, and the user's multiplier rides on top. The result is a CSS ratio
|
|
48
|
+
* against {@link BUBBLE_BASE_FONT_PX}, bounded so the text never drops below
|
|
49
|
+
* the readability floor or outgrows the pet. `bubbleScale` is optional at
|
|
50
|
+
* runtime: a host that predates the field (a rolling update, or any snapshot
|
|
51
|
+
* that omits it) falls back to the baseline, because a NaN ratio written into
|
|
52
|
+
* `--pet-bubble-scale` collapses every bubble's text to zero.
|
|
53
|
+
* @param display - display config; `bubbleScale` may be absent on older hosts.
|
|
54
|
+
* @returns the ratio written to `--pet-bubble-scale` (always finite).
|
|
55
|
+
*/
|
|
56
|
+
export declare function bubbleScaleFor(display: Pick<PetDisplayConfig, 'size'> & {
|
|
57
|
+
bubbleScale?: number;
|
|
58
|
+
}): number;
|
|
27
59
|
/** Everything persisted for the pet. */
|
|
28
60
|
export interface PetPersist {
|
|
29
61
|
/** Selected pet id (a registry entry; clamped at service startup). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAErD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEhE,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAEpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAErD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEhE,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAMlC,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,gBAAgB,OAAO,CAAA;AACpC,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAEvC,8CAA8C;AAC9C,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,gBAAgB,IAAI,CAAA;AACjC,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,KAAK,CAAA;AACrC,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,MAAM,CAAA;AACtC,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,KAAK,CAAA;AACpC,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAWzG;AAED,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,gCAAgC;IAChC,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,gBAAgB,CAAA;IACzB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAC3C;AAED,wBAAwB;AACxB,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,wBAAgB,YAAY,IAAI,UAAU,CAUzC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAmFD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAqB,GAAG,UAAU,CAuDrE;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAMjF"}
|
package/lib/types/persist.js
CHANGED
|
@@ -16,11 +16,46 @@ export const defaultDisplayConfig = {
|
|
|
16
16
|
size: 160,
|
|
17
17
|
right: 24,
|
|
18
18
|
bottom: 120,
|
|
19
|
+
bubbleScale: 1,
|
|
19
20
|
};
|
|
20
21
|
/** Display value bounds (shared by load-time validation and setConfig). */
|
|
21
22
|
export const DISPLAY_SIZE_MIN = 32;
|
|
22
23
|
export const DISPLAY_SIZE_MAX = 1024;
|
|
23
24
|
export const DISPLAY_INSET_MAX = 10_000;
|
|
25
|
+
/** Bubble typography bounds (issue #1549). */
|
|
26
|
+
export const BUBBLE_SCALE_MIN = 0.5;
|
|
27
|
+
export const BUBBLE_SCALE_MAX = 2;
|
|
28
|
+
/** Pixel size the bubble stylesheet was drawn for, at the default pet size. */
|
|
29
|
+
export const BUBBLE_BASE_FONT_PX = 12;
|
|
30
|
+
/** Pet size that baseline matches; other sizes scale the bubble with them. */
|
|
31
|
+
export const BUBBLE_BASE_SIZE_PX = 160;
|
|
32
|
+
/** Readability floor and layout ceiling of the scaled bubble text. */
|
|
33
|
+
export const BUBBLE_FONT_MIN_PX = 10;
|
|
34
|
+
export const BUBBLE_FONT_MAX_PX = 24;
|
|
35
|
+
/**
|
|
36
|
+
* Bubble typography scale for one display config (issue #1549): the bubble
|
|
37
|
+
* follows the pet's own size so a shrunk pet does not carry a full-size
|
|
38
|
+
* bubble, and the user's multiplier rides on top. The result is a CSS ratio
|
|
39
|
+
* against {@link BUBBLE_BASE_FONT_PX}, bounded so the text never drops below
|
|
40
|
+
* the readability floor or outgrows the pet. `bubbleScale` is optional at
|
|
41
|
+
* runtime: a host that predates the field (a rolling update, or any snapshot
|
|
42
|
+
* that omits it) falls back to the baseline, because a NaN ratio written into
|
|
43
|
+
* `--pet-bubble-scale` collapses every bubble's text to zero.
|
|
44
|
+
* @param display - display config; `bubbleScale` may be absent on older hosts.
|
|
45
|
+
* @returns the ratio written to `--pet-bubble-scale` (always finite).
|
|
46
|
+
*/
|
|
47
|
+
export function bubbleScaleFor(display) {
|
|
48
|
+
// Guard the arithmetic, not just the clamp: Math.min/max propagate NaN, so a
|
|
49
|
+
// missing or non-finite field would otherwise reach the stylesheet.
|
|
50
|
+
const size = Number.isFinite(display.size) ? display.size : BUBBLE_BASE_SIZE_PX;
|
|
51
|
+
const multiplier = typeof display.bubbleScale === 'number' && Number.isFinite(display.bubbleScale)
|
|
52
|
+
? display.bubbleScale
|
|
53
|
+
: 1;
|
|
54
|
+
const scaled = (size / BUBBLE_BASE_SIZE_PX) * multiplier;
|
|
55
|
+
const min = BUBBLE_FONT_MIN_PX / BUBBLE_BASE_FONT_PX;
|
|
56
|
+
const max = BUBBLE_FONT_MAX_PX / BUBBLE_BASE_FONT_PX;
|
|
57
|
+
return Math.round(Math.min(max, Math.max(min, scaled)) * 100) / 100;
|
|
58
|
+
}
|
|
24
59
|
/** Name constraints. */
|
|
25
60
|
export const PET_NAME_MAX_LENGTH = 20;
|
|
26
61
|
export function emptyPersist() {
|
|
@@ -155,6 +190,8 @@ export function loadPetPersist(dir = petHomeDir()) {
|
|
|
155
190
|
size: Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(DISPLAY_SIZE_MIN, finiteNum(rawDisplay.size, base.display.size)))),
|
|
156
191
|
right: Math.round(clamp(finiteNum(rawDisplay.right, base.display.right), DISPLAY_INSET_MAX)),
|
|
157
192
|
bottom: Math.round(clamp(finiteNum(rawDisplay.bottom, base.display.bottom), DISPLAY_INSET_MAX)),
|
|
193
|
+
// Fractional on purpose: the multiplier is a ratio, not a pixel count.
|
|
194
|
+
bubbleScale: Math.min(BUBBLE_SCALE_MAX, Math.max(BUBBLE_SCALE_MIN, finiteNum(rawDisplay.bubbleScale, base.display.bubbleScale))),
|
|
158
195
|
};
|
|
159
196
|
const petId = typeof parsed.petId === 'string' && parsed.petId.trim() !== ''
|
|
160
197
|
? parsed.petId.trim()
|
package/lib/types/service.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ export interface PetSettingsSection {
|
|
|
57
57
|
right: number;
|
|
58
58
|
/** Vertical inset from the viewport bottom edge, px. */
|
|
59
59
|
bottom: number;
|
|
60
|
+
/** Bubble typography multiplier (#1549); see PetDisplayConfig. */
|
|
61
|
+
bubbleScale?: number;
|
|
60
62
|
/** Master switch for the plugin (browser half + host routes). */
|
|
61
63
|
enabled?: boolean;
|
|
62
64
|
/**
|
|
@@ -332,7 +334,7 @@ export declare class PetService extends Service {
|
|
|
332
334
|
ok: false;
|
|
333
335
|
error: string;
|
|
334
336
|
}>;
|
|
335
|
-
/** RPC: update display config (size / position).
|
|
337
|
+
/** RPC: update display config (size / position / bubble scale). Pixel values are clamped to whole pixels. */
|
|
336
338
|
setConfig(patch: Partial<PetDisplayConfig>): Promise<{
|
|
337
339
|
ok: true;
|
|
338
340
|
display: PetDisplayConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACpF,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAC1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAS9C,OAAO,EAAgC,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAA;AACxF,OAAO,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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"}
|
package/lib/types/service.js
CHANGED
|
@@ -15,7 +15,7 @@ import { Service } from '@deepseek-ai/cordis';
|
|
|
15
15
|
import { announcementFresh, parseAnnouncement } from "./announce.js";
|
|
16
16
|
import { emptyProjectionRuntime, isActivityPhase, projectAssistantStreamFrame, projectOfficialEvent, } from "./event-projection.js";
|
|
17
17
|
import { PetLedger } from "./ledger.js";
|
|
18
|
-
import { DEFAULT_PET_NAME, DISPLAY_INSET_MAX, DISPLAY_SIZE_MAX, DISPLAY_SIZE_MIN, PET_NAME_MAX_LENGTH, loadPetPersist, petHomeDir, savePetPersist, } from "./persist.js";
|
|
18
|
+
import { DEFAULT_PET_NAME, DISPLAY_INSET_MAX, DISPLAY_SIZE_MAX, BUBBLE_SCALE_MAX, BUBBLE_SCALE_MIN, DISPLAY_SIZE_MIN, PET_NAME_MAX_LENGTH, loadPetPersist, petHomeDir, savePetPersist, } from "./persist.js";
|
|
19
19
|
import { DEFAULT_DECORATION_ID, decorationView, loadPetRegistry, petEntryView, petPackageRoot, } from "./registry.js";
|
|
20
20
|
import { WHISPER_TTL_MS } from "./chatter.js";
|
|
21
21
|
import { mergeVoicePacks } from "./voice-pack.js";
|
|
@@ -532,12 +532,13 @@ export class PetService extends Service {
|
|
|
532
532
|
this.flush();
|
|
533
533
|
return { ok: true, skin };
|
|
534
534
|
}
|
|
535
|
-
/** RPC: update display config (size / position).
|
|
535
|
+
/** RPC: update display config (size / position / bubble scale). Pixel values are clamped to whole pixels. */
|
|
536
536
|
async setConfig(patch) {
|
|
537
537
|
const next = { ...this.ledger.snapshot.display, ...patch };
|
|
538
538
|
next.size = Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(DISPLAY_SIZE_MIN, next.size)));
|
|
539
539
|
next.right = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, next.right)));
|
|
540
540
|
next.bottom = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, next.bottom)));
|
|
541
|
+
next.bubbleScale = Math.min(BUBBLE_SCALE_MAX, Math.max(BUBBLE_SCALE_MIN, next.bubbleScale));
|
|
541
542
|
this.ledger.setDisplay(next);
|
|
542
543
|
this.flush();
|
|
543
544
|
this.syncSettingsFromPet();
|
|
@@ -577,6 +578,7 @@ export class PetService extends Service {
|
|
|
577
578
|
next.size = Math.round(Math.min(DISPLAY_SIZE_MAX, Math.max(DISPLAY_SIZE_MIN, section.size)));
|
|
578
579
|
next.right = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.right)));
|
|
579
580
|
next.bottom = Math.round(Math.min(DISPLAY_INSET_MAX, Math.max(0, section.bottom)));
|
|
581
|
+
next.bubbleScale = Math.min(BUBBLE_SCALE_MAX, Math.max(BUBBLE_SCALE_MIN, section.bubbleScale ?? next.bubbleScale));
|
|
580
582
|
this.ledger.setDisplay(next);
|
|
581
583
|
this.flush();
|
|
582
584
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-pet",
|
|
3
3
|
"description": "Multi-pet companion plugin for the dsh web GUI: a registry-driven floating pet that reacts to model activity, with per-pet naming, petting/feeding interactions and an affinity score",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.23",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
|
@@ -61,7 +61,7 @@ const hiddenSnapshot: PetStateView = {
|
|
|
61
61
|
petCooldown: false,
|
|
62
62
|
feedCooldown: false,
|
|
63
63
|
},
|
|
64
|
-
display: { visible: false, size: 160, right: 24, bottom: 20 },
|
|
64
|
+
display: { visible: false, size: 160, right: 24, bottom: 20, bubbleScale: 1 },
|
|
65
65
|
pet: { id: 'whale-girl', displayName: '鲸鱼娘', description: '测试用鲸鱼娘' },
|
|
66
66
|
name: '泡泡',
|
|
67
67
|
treats: { stocked: 0, max: 5 },
|
|
@@ -63,7 +63,7 @@ export type PetDockEntryProps =
|
|
|
63
63
|
portalTarget?: Element
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const DEFAULT_DISPLAY: PetDisplayConfig = { visible: true, size: 160, right: 24, bottom: 20 }
|
|
66
|
+
const DEFAULT_DISPLAY: PetDisplayConfig = { visible: true, size: 160, right: 24, bottom: 20, bubbleScale: 1 }
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Dock entry: while the pet is visible, mount the floating PetSprite (it
|
|
@@ -29,6 +29,8 @@ export interface PetSettings {
|
|
|
29
29
|
right?: number
|
|
30
30
|
/** Vertical inset from the viewport bottom edge, px. */
|
|
31
31
|
bottom?: number
|
|
32
|
+
/** Bubble typography multiplier on the automatic size following (#1549). */
|
|
33
|
+
bubbleScale?: number
|
|
32
34
|
/** Selected pet id (a registry entry). */
|
|
33
35
|
petId?: string
|
|
34
36
|
/** Status-decoration master switch (pet-center M5, #567). */
|
|
@@ -47,6 +49,8 @@ export interface PetSettingsCardState extends CardShell {
|
|
|
47
49
|
right: CardFieldState
|
|
48
50
|
/** Bottom inset. */
|
|
49
51
|
bottom: CardFieldState
|
|
52
|
+
/** Bubble typography multiplier. */
|
|
53
|
+
bubbleScale: CardFieldState
|
|
50
54
|
/** Selected pet. */
|
|
51
55
|
petId: CardFieldState
|
|
52
56
|
/** Status-decoration master switch. */
|
|
@@ -117,6 +121,7 @@ export class PetSettingsCardController {
|
|
|
117
121
|
numberField('size'),
|
|
118
122
|
numberField('right'),
|
|
119
123
|
numberField('bottom'),
|
|
124
|
+
numberField('bubbleScale'),
|
|
120
125
|
choiceField('petId', this.petChoices),
|
|
121
126
|
])
|
|
122
127
|
this.store = this.form.bind(() => this.projection())
|
|
@@ -175,6 +180,7 @@ export class PetSettingsCardController {
|
|
|
175
180
|
size: this.form.field('size'),
|
|
176
181
|
right: this.form.field('right'),
|
|
177
182
|
bottom: this.form.field('bottom'),
|
|
183
|
+
bubbleScale: this.form.field('bubbleScale'),
|
|
178
184
|
petId: this.form.field('petId'),
|
|
179
185
|
petChoices: this.petChoices.map(id => ({ value: id, label: this.petLabels.get(id) ?? id })),
|
|
180
186
|
petDiagnostics: this.diagnostics,
|
|
@@ -321,6 +327,16 @@ export function PetSettingsCard(props: PetSettingsCardProps) {
|
|
|
321
327
|
onEdit={(text) => { props.edit('bottom', text) }}
|
|
322
328
|
onReset={() => { props.resetField('bottom') }}
|
|
323
329
|
/>
|
|
330
|
+
<ValueField
|
|
331
|
+
id="settings-pet-bubble-scale"
|
|
332
|
+
label={t('settings.bubbleScale')}
|
|
333
|
+
hint={t('settings.bubbleScaleHint')}
|
|
334
|
+
numeric
|
|
335
|
+
{...fieldProps}
|
|
336
|
+
{...state.bubbleScale}
|
|
337
|
+
onEdit={(text) => { props.edit('bubbleScale', text) }}
|
|
338
|
+
onReset={() => { props.resetField('bubbleScale') }}
|
|
339
|
+
/>
|
|
324
340
|
</PluginSettingsCard>
|
|
325
341
|
)
|
|
326
342
|
}
|