koishi-plugin-vsinger-gacha 1.4.0 → 1.4.2

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/lib/handbook.js CHANGED
@@ -41,8 +41,8 @@ const LABEL_H = 62;
41
41
  const GAP = 12;
42
42
  const PAD = 24;
43
43
  const HEAD = 128;
44
- const POOL_TITLE_H = 34;
45
- const SERIES_H = 44;
44
+ const POOL_TITLE_H = 46;
45
+ const SERIES_H = 50;
46
46
  const COLS_PER_COL = 8;
47
47
  const COLW = COLS_PER_COL * TW + (COLS_PER_COL - 1) * GAP;
48
48
  const ROWH = TH + LABEL_H;
@@ -134,12 +134,17 @@ async function render({ game, store, uid, displayName, outDir, tagsDir, thumbsDi
134
134
 
135
135
  // 每池一块(顺序填充)
136
136
  const blocks = [];
137
+ let _lastAct = null;
137
138
  for (const [act, pm] of seriesMap) {
138
139
  for (const [pool, arr] of pm) {
139
140
  arr.sort((a, b) => Number(b.v.rate_pct || 0) - Number(a.v.rate_pct || 0));
140
141
  const rows = Math.max(1, Math.ceil(arr.length / COLS_PER_COL));
141
142
  const got = arr.filter((c) => (owned[c.h] || 0) > 0).length;
142
- blocks.push({ act, pool, arr, got, h: POOL_TITLE_H + rows * ROWH + 12 });
143
+ const isNewSeries = act !== _lastAct;
144
+ // ★ 2026-11-05:系列头也要占高度,否则下一块会压到上一块的卡片上
145
+ const h = POOL_TITLE_H + rows * ROWH + 12 + (isNewSeries ? SERIES_H : 0);
146
+ blocks.push({ act, pool, arr, got, series: isNewSeries, h });
147
+ _lastAct = act;
143
148
  }
144
149
  }
145
150
  const totalH = blocks.reduce((a, b) => a + b.h, 0);
@@ -231,24 +236,32 @@ async function render({ game, store, uid, displayName, outDir, tagsDir, thumbsDi
231
236
  let prevAct = null;
232
237
  for (const blk of grp) {
233
238
  if (blk.act !== prevAct) {
234
- kit.panel(g, x0, y, COLW, SERIES_H - 8, { radius: 14, fill: 'rgba(255,255,255,0.88)' });
239
+ const sh = SERIES_H - 8;
240
+ kit.panel(g, x0, y + 2, COLW, sh, { radius: 14, fill: 'rgba(255,255,255,0.88)' });
235
241
  g.fillStyle = COLOR.accent;
236
- kit.roundRect(g, x0 + 12, y + 12, 5, SERIES_H - 32, 3);
242
+ kit.roundRect(g, x0 + 12, y + 2 + (sh - 20) / 2, 5, 20, 3);
237
243
  g.fill();
238
244
  g.fillStyle = COLOR.text;
239
- g.font = 'bold 21px VSingerSans, sans-serif';
240
- g.fillText(blk.act, x0 + 26, y + 22);
245
+ g.font = 'bold 20px VSingerSans, sans-serif';
246
+ g.textBaseline = 'middle';
247
+ g.fillText(blk.act, x0 + 26, y + 2 + sh / 2);
248
+ g.textBaseline = 'top';
241
249
  y += SERIES_H;
242
250
  prevAct = blk.act;
243
251
  }
244
252
  // 池标题(玻璃条)
245
- kit.panel(g, x0, y, COLW, POOL_TITLE_H - 10, { radius: 12, fill: 'rgba(255,255,255,0.78)' });
253
+ const ph = POOL_TITLE_H - 10;
254
+ kit.panel(g, x0, y + 1, COLW, ph, { radius: 12, fill: 'rgba(255,255,255,0.78)' });
255
+ g.textBaseline = 'middle';
246
256
  g.fillStyle = COLOR.accent;
247
- g.font = 'bold 21px VSingerSans, sans-serif';
248
- g.fillText(`${blk.pool}`, x0 + 12, y + 12);
257
+ g.font = 'bold 18px VSingerSans, sans-serif';
258
+ g.fillText(kit.fit(g, blk.pool, 'bold 18px VSingerSans, sans-serif', COLW - 100), x0 + 12, y + 1 + ph / 2);
249
259
  g.fillStyle = COLOR.textSub;
250
- g.font = '18px VSingerSans, sans-serif';
251
- g.fillText(`${blk.got}/${blk.arr.length}`, x0 + COLW - 82, y + 14);
260
+ g.font = '16px VSingerSans, sans-serif';
261
+ g.textAlign = 'right';
262
+ g.fillText(`${blk.got}/${blk.arr.length}`, x0 + COLW - 12, y + 1 + ph / 2);
263
+ g.textAlign = 'left';
264
+ g.textBaseline = 'top';
252
265
 
253
266
  for (let i = 0; i < blk.arr.length; i++) {
254
267
  const c = blk.arr[i];
package/lib/render/kit.js CHANGED
@@ -76,16 +76,20 @@ function header(g, o) {
76
76
  const W = o.W;
77
77
 
78
78
  // 圆形图标
79
- const R = 22;
79
+ const R = 24;
80
+ const cx = x + R;
81
+ const cy = y + R;
80
82
  g.save();
81
83
  g.beginPath();
82
- g.arc(x + R, y + R + 4, R, 0, Math.PI * 2);
84
+ g.arc(cx, cy, R, 0, Math.PI * 2);
83
85
  g.fillStyle = COLOR.accent;
84
86
  g.fill();
85
87
  g.fillStyle = '#fff';
86
- g.font = `bold 22px ${FONT}`;
88
+ g.font = `bold 26px ${FONT}`;
89
+ g.textAlign = 'center';
87
90
  g.textBaseline = 'middle';
88
- g.fillText('♪', x + R - 8, y + R + 4);
91
+ g.fillText('♪', cx, cy + 1);
92
+ g.textAlign = 'left';
89
93
  g.restore();
90
94
 
91
95
  g.textBaseline = 'top';
@@ -193,12 +197,12 @@ async function card(g, Canvas, o) {
193
197
 
194
198
  g.fillStyle = o.owned === false ? COLOR.textDim : COLOR.text;
195
199
  g.font = `bold ${o.nameSize || FONT_SIZE.h3}px ${FONT}`;
196
- g.fillText(fit(g, o.name, `bold ${o.nameSize || FONT_SIZE.h3}px ${FONT}`, w), o.x, o.y + h + 8);
200
+ g.fillText(fit(g, o.name, `bold ${o.nameSize || FONT_SIZE.h3}px ${FONT}`, w), o.x, o.y + h + 6);
197
201
  if (o.rate != null || o.tierName) {
198
202
  g.fillStyle = tc;
199
203
  g.font = `${o.metaSize || FONT_SIZE.meta}px ${FONT}`;
200
204
  const meta = `${o.tierName || (TIER[tier] || TIER[10]).name}${o.rate != null ? ' ' + o.rate + '%' : ''}`;
201
- g.fillText(fit(g, meta, `${o.metaSize || FONT_SIZE.meta}px ${FONT}`, w), o.x, o.y + h + 32);
205
+ g.fillText(fit(g, meta, `${o.metaSize || FONT_SIZE.meta}px ${FONT}`, w), o.x, o.y + h + 30);
202
206
  }
203
207
  }
204
208
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-vsinger-gacha",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "VSinger 收藏集抽卡 / 签到积分 / 图鉴(Koishi 插件,一次性安装)",
5
5
  "main": "lib/index.js",
6
6
  "files": [