dsh-live2dwaifu 1.0.1 → 1.0.3

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.md CHANGED
@@ -35,7 +35,9 @@ dsh plugin --profile desktop add dsh-live2dwaifu
35
35
 
36
36
  ### 位置和大小
37
37
 
38
- 按住**标题栏**能拖到屏幕任何地方;右下角那个小斜纹拖的是大小(宽 200–720,高 220–视口高−80)。位置、大小、背景、开合状态都记在本机,下次打开还是这样。
38
+ 按住**标题栏**能拖到屏幕任何地方。
39
+ **改大小**:卡片左上角那个小斜纹,往左上拖变大、往右下拖变小——卡片本身钉在屏幕右下角,所以动的是它的左上角(宽 200–720,高 220–视口高−80)。
40
+ 位置、大小、背景、开合状态都记在本机,下次打开还是这样。
39
41
 
40
42
  拖到一半跑到屏幕外了?关掉重开一次就回到默认位置。
41
43
 
@@ -188,6 +190,19 @@ python tools/export-dsh-meme.py
188
190
 
189
191
  | 开关 | 位置 | 默认 | 说明 |
190
192
  |---|---|---|---|
193
+ | 视线跟随鼠标 | 本机 | 开 | 角色的眼睛和头跟着鼠标动 |
194
+ | 点击角色有反应 | 本机 | 开 | 点她不同部位有不同反应 |
195
+ | 自动播放动作 | 本机 | 开 | 模型带动作文件时,隔一会儿播一个 |
196
+ | 说话带电子音 | 本机 | 开 | 每个字一声短音 |
197
+ | 复述聊天内容 | 本机 | 开 | 聊天窗口出现新回复时,由她念出来 |
198
+ | 闲置时主动说话 | 服务端 | 开 | 一段时间没人说话,她自己开一句 |
199
+ | 回复附带选项按钮 | 服务端 | 开 | 她觉得需要选择时,气泡上方出现可点按钮 |
200
+ | 记住聊过的内容 | 服务端 | 开 | 关掉就不带记忆、不压缩 |
201
+ | 表情包(四档) | 服务端 | 不使用 | 测试功能,见上面那节 |
202
+
203
+ 「本机」存 localStorage,只影响这一台浏览器;「服务端」存 `~/.dsh/dsh-live2d/config.json`,换浏览器也一样。
204
+
205
+ ---|---|---|---|
191
206
  | 眼睛跟着鼠标 | 本机 | 开 | 关掉她就不看鼠标了 |
192
207
  | 点她有反应 | 本机 | 开 | 摸头害羞、戳身上瞪你 |
193
208
  | 自己播动作 | 本机 | 开 | 有动作文件的模型才会动 |
@@ -272,7 +287,7 @@ curl -X POST http://127.0.0.1:<端口>/dsh-live2d/api/push \
272
287
  先重启。还不来,看 profile 的 `package.json`:`dsh.profile.bundles` 和 `dependencies` 里都得有 `dsh-live2dwaifu`。手动拷进 `node_modules` 的不会自动登记。
273
288
 
274
289
  **她只有半张脸 / 位置偏上**
275
- 模型画布比例跟卡片不一样。卡片是竖的,太宽或太扁的模型会被裁两边。拖右下角改形状试试。
290
+ 模型画布比例跟卡片不一样。卡片是竖的,太宽或太扁的模型会被裁两边。拖左上角那个小斜纹改形状试试。
276
291
 
277
292
  **导入了却不认得**
278
293
  `.model3.json` 的层级选错了。选它隔壁那一层。
package/assets/viewer.js CHANGED
@@ -44338,30 +44338,43 @@ void main(void)\r
44338
44338
  }
44339
44339
  }
44340
44340
  var LOCAL_OPTS = [
44341
- ["gaze", "\u773C\u775B\u8DDF\u7740\u9F20\u6807"],
44342
- ["poke", "\u70B9\u5979\u6709\u53CD\u5E94"],
44343
- ["motion", "\u81EA\u5DF1\u64AD\u52A8\u4F5C"],
44344
- ["sound", "\u51FA\u58F0"],
44345
- ["follow", "\u8DDF\u7740\u804A\u5929\u5FF5"]
44341
+ ["gaze", "\u89C6\u7EBF\u8DDF\u968F\u9F20\u6807"],
44342
+ ["poke", "\u70B9\u51FB\u89D2\u8272\u6709\u53CD\u5E94"],
44343
+ ["motion", "\u81EA\u52A8\u64AD\u653E\u52A8\u4F5C"],
44344
+ ["sound", "\u8BF4\u8BDD\u5E26\u7535\u5B50\u97F3"],
44345
+ ["follow", "\u590D\u8FF0\u804A\u5929\u5185\u5BB9"]
44346
44346
  ];
44347
44347
  var SERVER_OPTS = [
44348
- ["proactive", "\u6CA1\u4EBA\u7406\u5C31\u81EA\u5DF1\u5F00\u53E3"],
44349
- ["choices", "\u7ED9\u9009\u9879\u8BA9\u4ED6\u6311"],
44350
- ["memory", "\u8BB0\u4F4F\u4E4B\u524D\u8BF4\u7684"]
44348
+ ["proactive", "\u95F2\u7F6E\u65F6\u4E3B\u52A8\u8BF4\u8BDD"],
44349
+ ["choices", "\u56DE\u590D\u9644\u5E26\u9009\u9879\u6309\u94AE"],
44350
+ ["memory", "\u8BB0\u4F4F\u804A\u8FC7\u7684\u5185\u5BB9"]
44351
44351
  ];
44352
+ var LOCAL_HINT = {
44353
+ gaze: "\u89D2\u8272\u7684\u773C\u775B\u548C\u5934\u4F1A\u8DDF\u7740\u9F20\u6807\u79FB\u52A8",
44354
+ poke: "\u70B9\u89D2\u8272\u7684\u4E0D\u540C\u90E8\u4F4D\u4F1A\u6709\u4E0D\u540C\u53CD\u5E94",
44355
+ motion: "\u6A21\u578B\u5E26\u52A8\u4F5C\u6587\u4EF6\u65F6\uFF0C\u9694\u4E00\u4F1A\u513F\u81EA\u52A8\u64AD\u4E00\u4E2A",
44356
+ sound: "\u8BF4\u8BDD\u65F6\u6BCF\u4E2A\u5B57\u53D1\u4E00\u58F0\u5F88\u77ED\u7684\u7535\u5B50\u97F3",
44357
+ follow: "\u804A\u5929\u7A97\u53E3\u51FA\u73B0\u65B0\u56DE\u590D\u65F6\uFF0C\u7531\u89D2\u8272\u5FF5\u51FA\u6765"
44358
+ };
44359
+ var SERVER_HINT = {
44360
+ proactive: "\u4E00\u6BB5\u65F6\u95F4\u6CA1\u4EBA\u8BF4\u8BDD\uFF0C\u89D2\u8272\u81EA\u5DF1\u5F00\u4E00\u53E5",
44361
+ choices: "\u89D2\u8272\u89C9\u5F97\u9700\u8981\u9009\u62E9\u65F6\uFF0C\u6C14\u6CE1\u4E0A\u65B9\u51FA\u73B0\u53EF\u70B9\u7684\u6309\u94AE",
44362
+ memory: "\u4FDD\u7559\u804A\u8FC7\u7684\u5185\u5BB9\uFF0C\u4E0B\u6B21\u63A5\u7740\u804A\uFF08\u5360\u66F4\u591A\u6A21\u578B\u989D\u5EA6\uFF09"
44363
+ };
44352
44364
  var MEME_MODES = ["off", "own", "both", "external"];
44353
- var MEME_LABELS = ["\u4E0D\u4F7F\u7528", "\u53EA\u4F7F\u7528\u81EA\u5E26", "\u5747\u5F00\u542F", "\u53EA\u7528 dsh-meme"];
44365
+ var MEME_LABELS = ["\u4E0D\u4F7F\u7528", "\u4EC5\u81EA\u5E26", "\u4E24\u8005\u90FD\u7528", "\u4EC5 dsh-meme"];
44354
44366
  var serverSettings = {};
44355
44367
  function renderSettings() {
44356
44368
  const box = $2("settings");
44357
44369
  if (!box) return;
44358
44370
  box.innerHTML = "";
44359
44371
  const h1 = document.createElement("h3");
44360
- h1.textContent = "\u8FD9\u53F0\u673A\u5668\u4E0A";
44372
+ h1.textContent = "\u663E\u793A\u4E0E\u4EA4\u4E92\uFF08\u5B58\u672C\u673A\uFF09";
44361
44373
  box.appendChild(h1);
44362
44374
  for (const [k2, label] of LOCAL_OPTS) {
44363
44375
  const row = document.createElement("label");
44364
44376
  row.className = "opt";
44377
+ row.title = LOCAL_HINT[k2] || "";
44365
44378
  const cb = document.createElement("input");
44366
44379
  cb.type = "checkbox";
44367
44380
  cb.checked = flag(k2);
@@ -44371,11 +44384,12 @@ void main(void)\r
44371
44384
  box.appendChild(row);
44372
44385
  }
44373
44386
  const h2 = document.createElement("h3");
44374
- h2.textContent = "\u5979\u90A3\u8FB9";
44387
+ h2.textContent = "\u5BF9\u8BDD\u4E0E\u884C\u4E3A\uFF08\u5B58\u670D\u52A1\u7AEF\uFF09";
44375
44388
  box.appendChild(h2);
44376
44389
  for (const [k2, label] of SERVER_OPTS) {
44377
44390
  const row = document.createElement("label");
44378
44391
  row.className = "opt";
44392
+ row.title = SERVER_HINT[k2] || "";
44379
44393
  const cb = document.createElement("input");
44380
44394
  cb.type = "checkbox";
44381
44395
  cb.checked = serverSettings[k2] !== false;
@@ -44422,7 +44436,7 @@ void main(void)\r
44422
44436
  };
44423
44437
  const note = document.createElement("div");
44424
44438
  note.className = "opt-note";
44425
- note.textContent = "\u81EA\u5E26\u90A3\u5957\u662F\u590F\u94C3\u7684 Q \u7248\u8D34\u7EB8\uFF0C\u4E8C\u5341\u5F20\uFF1Bdsh-meme \u90A3\u5957\u501F\u7528\u4F60\u672C\u673A\u5DF2\u7ECF\u88C5\u7684\u56FE\u5E93\u3002\u529F\u80FD\u8FD8\u5728\u8BD5\u9A8C\uFF0C\u53EF\u80FD\u4F1A\u8C03\u3002";
44439
+ note.textContent = "\u9009\u8BF4\u8BDD\u65F6\u914D\u56FE\u7684\u6765\u6E90\uFF1A\u81EA\u5E26\u662F\u63D2\u4EF6\u5185\u7F6E\u7684\u8D34\u56FE\uFF1Bdsh-meme \u662F\u4F60\u5DF2\u7ECF\u88C5\u597D\u7684\u56FE\u5E93\u3002\u6B64\u529F\u80FD\u4ECD\u5728\u6D4B\u8BD5\uFF0C\u884C\u4E3A\u53EF\u80FD\u8C03\u6574\u3002";
44426
44440
  wrap.appendChild(slider);
44427
44441
  wrap.appendChild(lab);
44428
44442
  wrap.appendChild(note);
package/lib/client.js CHANGED
@@ -18,7 +18,7 @@
18
18
  transition:box-shadow .2s ease}
19
19
  .dsh-l2d-card:hover{box-shadow:0 22px 58px rgba(0,0,0,.58)}
20
20
  .dsh-l2d-card.collapsed{width:150px!important;height:38px!important}
21
- .dsh-l2d-head{display:flex;align-items:center;gap:7px;padding:9px 11px;color:#a8b1bf;font-size:11px;
21
+ .dsh-l2d-head{display:flex;align-items:center;gap:7px;padding:9px 11px 9px 24px;color:#a8b1bf;font-size:11px;
22
22
  letter-spacing:.4px;border-bottom:1px solid rgba(255,255,255,.06);user-select:none;flex:none;cursor:move;
23
23
  background:linear-gradient(180deg,rgba(255,255,255,.045),rgba(255,255,255,0))}
24
24
  .dsh-l2d-dot{width:7px;height:7px;border-radius:50%;background:#6aa9ff;flex:none;
@@ -43,10 +43,12 @@
43
43
  transition:filter .15s ease}
44
44
  .dsh-l2d-send:hover{filter:brightness(1.14)}
45
45
  .dsh-l2d-send:active{filter:brightness(.96)}
46
- .dsh-l2d-grip{position:absolute;right:1px;bottom:1px;width:18px;height:18px;cursor:nwse-resize;opacity:.5;
47
- transition:opacity .15s ease;
48
- background:repeating-linear-gradient(135deg,transparent 0 2px,rgba(255,255,255,.4) 2px 3px) no-repeat right bottom/10px 10px}
49
- .dsh-l2d-grip:hover{opacity:1}
46
+ .dsh-l2d-grip{position:absolute;left:0;top:0;width:20px;height:20px;cursor:nwse-resize;opacity:.4;
47
+ transition:opacity .15s ease,background .15s ease;border-radius:16px 0 8px 0;z-index:2;
48
+ background:repeating-linear-gradient(135deg,transparent 0 2px,rgba(255,255,255,.45) 2px 3px) no-repeat left top/10px 10px}
49
+ .dsh-l2d-grip:hover{opacity:1;background-color:rgba(255,255,255,.08)}
50
+ .dsh-l2d-card.resizing{cursor:nwse-resize;box-shadow:0 0 0 1px rgba(106,169,255,.45),0 22px 58px rgba(0,0,0,.6)}
51
+ .dsh-l2d-card.moving{cursor:move;box-shadow:0 0 0 1px rgba(106,169,255,.35),0 22px 58px rgba(0,0,0,.6)}
50
52
  `;
51
53
 
52
54
  function ensureCss() {
@@ -149,42 +151,67 @@
149
151
  .catch(() => setTitle('Live2D'));
150
152
  }, [nonce]);
151
153
 
154
+ // 拖动时把 iframe 的指针事件关掉,否则光标一进 iframe 父窗口就收不到事件,手感像粘住
155
+ const lockPointer = (on, cls, cardEl) => {
156
+ const f = ref.current;
157
+ if (f) f.style.pointerEvents = on ? 'none' : '';
158
+ if (cardEl && cardEl.classList) {
159
+ cardEl.classList.toggle('resizing', on && cls === 'resizing');
160
+ cardEl.classList.toggle('moving', on && cls === 'moving');
161
+ }
162
+ document.body.style.userSelect = on ? 'none' : '';
163
+ };
164
+
165
+ const bindDrag = (move, cls, cardEl) => {
166
+ const up = () => {
167
+ window.removeEventListener('pointermove', move);
168
+ window.removeEventListener('pointerup', up);
169
+ window.removeEventListener('pointercancel', up);
170
+ lockPointer(false, cls, cardEl);
171
+ };
172
+ window.addEventListener('pointermove', move);
173
+ window.addEventListener('pointerup', up);
174
+ window.addEventListener('pointercancel', up);
175
+ };
176
+
177
+ // 卡片钉在右下角,所以只有左上角会动:往左上拖变大,往右下拖变小
152
178
  const startDrag = (e) => {
153
179
  e.preventDefault();
180
+ e.stopPropagation();
181
+ const cardEl = e.currentTarget.closest('.dsh-l2d-card');
154
182
  const sx = e.clientX;
155
183
  const sy = e.clientY;
156
184
  const w0 = size.w;
157
185
  const h0 = size.h;
158
- const move = (ev) => {
159
- const w = Math.max(200, Math.min(720, w0 + (sx - ev.clientX)));
160
- const hh = Math.max(220, Math.min(window.innerHeight - 80, h0 + (sy - ev.clientY)));
186
+ lockPointer(true, 'resizing', cardEl);
187
+ bindDrag((ev) => {
188
+ const maxW = Math.min(720, Math.max(240, window.innerWidth - 60));
189
+ const maxH = Math.max(240, window.innerHeight - 80);
190
+ const w = Math.max(200, Math.min(maxW, w0 + (sx - ev.clientX)));
191
+ const hh = Math.max(220, Math.min(maxH, h0 + (sy - ev.clientY)));
161
192
  setSize({ w: Math.round(w), h: Math.round(hh) });
162
- };
163
- const up = () => {
164
- window.removeEventListener('pointermove', move);
165
- window.removeEventListener('pointerup', up);
166
- };
167
- window.addEventListener('pointermove', move);
168
- window.addEventListener('pointerup', up);
193
+ }, 'resizing', cardEl);
169
194
  };
170
195
 
171
196
  const startMove = (e) => {
172
197
  if (e.button !== undefined && e.button !== 0) return;
198
+ const cardEl = e.currentTarget.closest('.dsh-l2d-card');
173
199
  const sx = e.clientX;
174
200
  const sy = e.clientY;
175
201
  const x0 = pos.x;
176
202
  const y0 = pos.y;
177
- const move = (ev) => {
203
+ const w = size.w;
204
+ const hh = open ? size.h : 38;
205
+ lockPointer(true, 'moving', cardEl);
206
+ bindDrag((ev) => {
178
207
  const nx = x0 + (ev.clientX - sx);
179
208
  const ny = y0 + (ev.clientY - sy);
180
- setPos({ x: Math.round(nx), y: Math.round(ny) });
181
- };
182
- const up = () => {
183
- window.removeEventListener('pointermove', move);
184
- window.removeEventListener('pointerup', up);
185
- };
186
- window.addEventListener('pointermove', move);
187
- window.addEventListener('pointerup', up);
209
+ // 至少留八十像素在视口里,别拖丢
210
+ setPos({
211
+ x: Math.round(Math.min(window.innerWidth - 80, Math.max(-w + 80, nx))),
212
+ y: Math.round(Math.min(window.innerHeight - 44, Math.max(-hh + 44, ny))),
213
+ });
214
+ }, 'moving', cardEl);
188
215
  };
189
216
  const noDrag = (e) => e.stopPropagation();
190
217
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-live2dwaifu",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "给 DSH 网页右下角请一个 Live2D 角色:会眨眼、会呼吸、视线跟着鼠标、点她有反应、说话时嘴动、心情变了眉毛跟着动。模型不用内置——谁装谁放自己的文件夹;支持自定义 .exp3.json 表情和 .motion3.json 动作,卡片能拖能缩,背景可换。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",