dsh-plugin-vrmpet3d 0.1.0 → 0.1.1
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 +2 -0
- package/desktop/main.js +45 -3
- package/desktop/preload.js +6 -2
- package/lib/client.core.js +209 -13
- package/lib/client.js +278 -42
- package/lib/config-page.html +71 -45
- package/lib/config-page.js +1120 -229
- package/lib/core.js +209 -13
- package/lib/desktop-page.js +144 -8
- package/lib/global-page.html +140 -99
- package/lib/index.js +150 -33
- package/lib/model-picker.js +139 -49
- package/lib/picker-page.html +34 -8
- package/lib/picker-page.js +192 -11
- package/lib/setup-page.html +68 -49
- package/lib/setup-page.js +395 -42
- package/lib/whale.js +191 -0
- package/package.json +1 -1
package/lib/config-page.html
CHANGED
|
@@ -3,11 +3,20 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
|
|
6
|
+
<!--
|
|
7
|
+
The title, the nav, the table headers and every row below carry `data-i18n*`, and the Chinese text stays INLINE as
|
|
8
|
+
the no-JS fallback: this page's script can fail to load (that is what the watchdog at the bottom reports), and a
|
|
9
|
+
page that failed should still read in one language rather than show nothing. `lib/config-page.js` owns the table
|
|
10
|
+
and `core.applyI18n` writes these places; a key the table lacks leaves the markup alone.
|
|
11
|
+
|
|
12
|
+
Both settings pages are written in the two languages by that ONE script and its ONE table, so a key here is shared
|
|
13
|
+
with 通用设置 — `sectionModel` names both this page's heading and its nav entry.
|
|
14
|
+
-->
|
|
15
|
+
<title data-i18n="titleModel">vrmpet3d · 模型参数</title>
|
|
7
16
|
<meta name="color-scheme" content="dark light">
|
|
8
17
|
<!--
|
|
9
|
-
The stylesheet both settings pages share. One file rather than a copy in each page: the two pages
|
|
10
|
-
|
|
18
|
+
The stylesheet both settings pages share. One file rather than a copy in each page: the two pages render
|
|
19
|
+
the same rows, tables and status lines, and a copy is how the two drift apart.
|
|
11
20
|
|
|
12
21
|
The MODEL page (`/vrmpet3d/config`). Its sections are the ones that are about ONE model, in this order:
|
|
13
22
|
模型 → 表情 → 部位 → 弹簧骨. Everything else (导入, 状态, 碎碎念, 视线, 鼠标互动, 其他) is a section of
|
|
@@ -27,44 +36,44 @@
|
|
|
27
36
|
-->
|
|
28
37
|
<div class="page-loading" role="status" aria-live="polite">
|
|
29
38
|
<span class="page-loading-spinner" aria-hidden="true"></span>
|
|
30
|
-
<span>正在加载设置…</span>
|
|
39
|
+
<span data-i18n="loading">正在加载设置…</span>
|
|
31
40
|
</div>
|
|
32
41
|
|
|
33
|
-
<header class="page-header"><div class="eyebrow">VRMPET3D · SETTINGS</div><h1>模型参数</h1><div id="status" role="status" aria-live="polite">正在读取…</div></header>
|
|
34
|
-
<nav class="section-nav" aria-label="设置分组"><a href="#settings-0">模型</a><a href="#settings-1">表情</a><a href="#settings-2">部位</a><a href="#settings-3">弹簧骨</a></nav>
|
|
42
|
+
<header class="page-header"><div class="eyebrow">VRMPET3D · SETTINGS</div><h1 data-i18n="headingModel">模型参数</h1><div id="status" role="status" aria-live="polite" data-i18n="reading">正在读取…</div></header>
|
|
43
|
+
<nav class="section-nav" aria-label="设置分组" data-i18n-aria="navSections"><a href="#settings-0" data-i18n="sectionModel">模型</a><a href="#settings-1" data-i18n="sectionExpression">表情</a><a href="#settings-2" data-i18n="sectionParts">部位</a><a href="#settings-3" data-i18n="sectionSprings">弹簧骨</a></nav>
|
|
35
44
|
<main>
|
|
36
45
|
<section class="settings-section" id="settings-0">
|
|
37
|
-
<h2>模型</h2>
|
|
46
|
+
<h2 data-i18n="sectionModel">模型</h2>
|
|
38
47
|
<div class="card">
|
|
39
48
|
<div class="row">
|
|
40
|
-
<label class="k" for="model-select">当前模型</label>
|
|
49
|
+
<label class="k" for="model-select" data-i18n="currentModel">当前模型</label>
|
|
41
50
|
<select id="model-select" class="grow"></select>
|
|
42
51
|
<span class="pill" id="model-spec">—</span>
|
|
43
52
|
</div>
|
|
44
|
-
<div class="row"><span class="k">可用信息</span><span class="grow note" id="model-meta">—</span></div>
|
|
53
|
+
<div class="row"><span class="k" data-i18n="availableInfo">可用信息</span><span class="grow note" id="model-meta">—</span></div>
|
|
45
54
|
</div>
|
|
46
55
|
|
|
47
56
|
</section>
|
|
48
57
|
|
|
49
58
|
<section class="settings-section" id="settings-1">
|
|
50
|
-
<h2
|
|
59
|
+
<h2><span data-i18n="sectionExpression">表情</span> <span id="expression-count"></span></h2>
|
|
51
60
|
<div class="card">
|
|
52
61
|
<div class="row">
|
|
53
|
-
<label class="k" for="blink-enabled">眨眼</label>
|
|
54
|
-
<label class="inline"><input type="checkbox" id="blink-enabled">
|
|
55
|
-
<span class="k sub">间隔</span>
|
|
62
|
+
<label class="k" for="blink-enabled" data-i18n="blink">眨眼</label>
|
|
63
|
+
<label class="inline"><input type="checkbox" id="blink-enabled"> <span data-i18n="on">开启</span></label>
|
|
64
|
+
<span class="k sub" data-i18n="interval">间隔</span>
|
|
56
65
|
<input type="number" id="blink-min" step="0.5" min="0.5" max="60"> –
|
|
57
|
-
<input type="number" id="blink-max" step="0.5" min="0.5" max="60">
|
|
66
|
+
<input type="number" id="blink-max" step="0.5" min="0.5" max="60"> <span data-i18n="secondsUnit">秒</span>
|
|
58
67
|
</div>
|
|
59
68
|
<div class="row">
|
|
60
|
-
<label class="k" for="emotion-enabled">情绪</label>
|
|
61
|
-
<label class="inline"><input type="checkbox" id="emotion-enabled">
|
|
62
|
-
<span class="k sub">空闲间隔</span>
|
|
69
|
+
<label class="k" for="emotion-enabled" data-i18n="emotion">情绪</label>
|
|
70
|
+
<label class="inline"><input type="checkbox" id="emotion-enabled"> <span data-i18n="on">开启</span></label>
|
|
71
|
+
<span class="k sub" data-i18n="idleInterval">空闲间隔</span>
|
|
63
72
|
<input type="number" id="emotion-idle-min" step="1" min="2" max="600"> –
|
|
64
|
-
<input type="number" id="emotion-idle-max" step="1" min="2" max="600">
|
|
73
|
+
<input type="number" id="emotion-idle-max" step="1" min="2" max="600"> <span data-i18n="secondsUnit">秒</span>
|
|
65
74
|
</div>
|
|
66
75
|
<table id="emotion-table">
|
|
67
|
-
<thead><tr><th style="width:76px">情境</th><th style="width:58px">使用</th><th>表情</th><th style="width:104px">持续时间</th></tr></thead>
|
|
76
|
+
<thead><tr><th style="width:76px" data-i18n="colSituation">情境</th><th style="width:58px" data-i18n="colUse">使用</th><th data-i18n="colExpression">表情</th><th style="width:104px" data-i18n="colHold">持续时间</th></tr></thead>
|
|
68
77
|
<tbody id="emotion-body"></tbody>
|
|
69
78
|
</table>
|
|
70
79
|
</div>
|
|
@@ -72,7 +81,7 @@
|
|
|
72
81
|
</section>
|
|
73
82
|
|
|
74
83
|
<section class="settings-section" id="settings-2">
|
|
75
|
-
<h2
|
|
84
|
+
<h2><span data-i18n="sectionParts">部位</span> <span id="part-count"></span></h2>
|
|
76
85
|
<!--
|
|
77
86
|
默认折叠(operator, 2026-10-14: 「"部位"区域默认折叠,内容太多了」).
|
|
78
87
|
|
|
@@ -83,22 +92,22 @@
|
|
|
83
92
|
the markup. The count beside the heading is filled whether the fold is open or shut.
|
|
84
93
|
-->
|
|
85
94
|
<details id="parts-fold">
|
|
86
|
-
<summary>展开部位列表</summary>
|
|
95
|
+
<summary data-i18n="partsExpand">展开部位列表</summary>
|
|
87
96
|
<div class="card">
|
|
88
97
|
<table id="part-table">
|
|
89
98
|
<thead><tr>
|
|
90
|
-
<th style="width:150px">部位</th>
|
|
91
|
-
<th style="width:58px">使用</th>
|
|
92
|
-
<th>表情</th>
|
|
93
|
-
<th style="width:104px">持续时间</th>
|
|
94
|
-
<th style="width:290px">结构</th>
|
|
99
|
+
<th style="width:150px" data-i18n="colPart">部位</th>
|
|
100
|
+
<th style="width:58px" data-i18n="colUse">使用</th>
|
|
101
|
+
<th data-i18n="colExpression">表情</th>
|
|
102
|
+
<th style="width:104px" data-i18n="colHold">持续时间</th>
|
|
103
|
+
<th style="width:290px" data-i18n="colStructure">结构</th>
|
|
95
104
|
<th style="width:58px"></th>
|
|
96
105
|
</tr></thead>
|
|
97
106
|
<tbody id="part-body"></tbody>
|
|
98
107
|
</table>
|
|
99
108
|
<div class="row" style="margin-top:10px">
|
|
100
|
-
<button id="part-add" type="button">新增部位</button>
|
|
101
|
-
<span class="note"
|
|
109
|
+
<button id="part-add" type="button" data-i18n="partsAdd">新增部位</button>
|
|
110
|
+
<span class="note"><span data-i18n="partsMaxPrefix">最多</span> <span id="part-max"></span><span data-i18n="partsMaxSuffix"> 个</span></span>
|
|
102
111
|
</div>
|
|
103
112
|
<!--
|
|
104
113
|
The structure BROWSER. It replaced a native `<input list>` + `<datalist>`: in the settings window that popup
|
|
@@ -107,9 +116,9 @@
|
|
|
107
116
|
-->
|
|
108
117
|
<div class="part-picker" id="part-picker" hidden>
|
|
109
118
|
<div class="part-picker-head">
|
|
110
|
-
<input type="text" id="part-picker-filter" placeholder="筛选结构名">
|
|
119
|
+
<input type="text" id="part-picker-filter" placeholder="筛选结构名" data-i18n-placeholder="filterStructures">
|
|
111
120
|
<span class="note" id="part-picker-count"></span>
|
|
112
|
-
<button type="button" id="part-picker-close">关闭</button>
|
|
121
|
+
<button type="button" id="part-picker-close" data-i18n="close">关闭</button>
|
|
113
122
|
</div>
|
|
114
123
|
<div class="part-picker-list" id="part-picker-list" tabindex="0"></div>
|
|
115
124
|
</div>
|
|
@@ -119,12 +128,12 @@
|
|
|
119
128
|
</section>
|
|
120
129
|
|
|
121
130
|
<section class="settings-section" id="settings-3">
|
|
122
|
-
<h2
|
|
131
|
+
<h2><span data-i18n="sectionSprings">弹簧骨</span> <span id="spring-count"></span></h2>
|
|
123
132
|
<div class="card">
|
|
124
133
|
<div id="spring-list"></div>
|
|
125
134
|
<div class="row" style="margin-top:10px">
|
|
126
|
-
<label class="k" for="spring-motion-physics">动作播放时</label>
|
|
127
|
-
<label class="inline"><input type="checkbox" id="spring-motion-physics">
|
|
135
|
+
<label class="k" for="spring-motion-physics" data-i18n="springMotionWhile">动作播放时</label>
|
|
136
|
+
<label class="inline"><input type="checkbox" id="spring-motion-physics"> <span data-i18n="springMotionBox">头发与裙摆继续摆动</span></label>
|
|
128
137
|
</div>
|
|
129
138
|
<!--
|
|
130
139
|
弹簧骨碰撞:全部关闭(默认)/ 全部开启 / 自定义(operator, 2026-10-14).
|
|
@@ -136,11 +145,11 @@
|
|
|
136
145
|
because comparing the two states in one sitting is the only way to answer 穿模 by looking.
|
|
137
146
|
-->
|
|
138
147
|
<div class="row" style="margin-top:10px">
|
|
139
|
-
<label class="k" for="spring-colliders">弹簧骨碰撞</label>
|
|
148
|
+
<label class="k" for="spring-colliders" data-i18n="springColliders">弹簧骨碰撞</label>
|
|
140
149
|
<select id="spring-colliders">
|
|
141
|
-
<option value="off">全部关闭(默认)</option>
|
|
142
|
-
<option value="all">全部开启</option>
|
|
143
|
-
<option value="custom">自定义</option>
|
|
150
|
+
<option value="off" data-i18n="collidersOff">全部关闭(默认)</option>
|
|
151
|
+
<option value="all" data-i18n="collidersAll">全部开启</option>
|
|
152
|
+
<option value="custom" data-i18n="collidersCustom">自定义</option>
|
|
144
153
|
</select>
|
|
145
154
|
</div>
|
|
146
155
|
<!--
|
|
@@ -152,11 +161,11 @@
|
|
|
152
161
|
no colliders shows no list rather than switches that do nothing.
|
|
153
162
|
-->
|
|
154
163
|
<details id="spring-colliders-detail" hidden style="margin-top:8px">
|
|
155
|
-
<summary
|
|
164
|
+
<summary><span data-i18n="collidersDetail">逐个碰撞体</span> <span id="spring-collider-count"></span></summary>
|
|
156
165
|
<div id="spring-collider-list" style="margin-top:8px;display:flex;flex-direction:column;gap:6px"></div>
|
|
157
166
|
</details>
|
|
158
167
|
<div class="row" style="margin-top:10px">
|
|
159
|
-
<button id="spring-reset-all">全部恢复默认</button>
|
|
168
|
+
<button id="spring-reset-all" data-i18n="springResetAll">全部恢复默认</button>
|
|
160
169
|
</div>
|
|
161
170
|
</div>
|
|
162
171
|
|
|
@@ -168,23 +177,40 @@
|
|
|
168
177
|
A settings page that can only say "正在读取…" is useless when something fails: the text is the HTML's
|
|
169
178
|
own placeholder, and a script that never ran, 404'd or threw at its first line looks exactly like a
|
|
170
179
|
slow host. So this runs FIRST, catches what it can, and after two seconds says what is actually wrong.
|
|
180
|
+
|
|
181
|
+
It runs BEFORE `lib/core.js`, which is the whole point — the case it exists for is a core that never
|
|
182
|
+
loaded — so it cannot use `core.textFor` and carries its own tiny map instead: three sentences plus the
|
|
183
|
+
brackets a filename goes in, picked from `navigator.language` in one line. Chinese is the fallback,
|
|
184
|
+
because the markup around it is Chinese. Keep it small: this is a watchdog, not a second i18n system.
|
|
171
185
|
-->
|
|
172
186
|
<script>
|
|
173
187
|
(function () {
|
|
188
|
+
var ZH = /^(zh|cn|chinese)/i.test(navigator.language || '');
|
|
189
|
+
var WORDS = ZH
|
|
190
|
+
? {
|
|
191
|
+
error: "页面脚本出错:",
|
|
192
|
+
file: "(来自 {name})",
|
|
193
|
+
coreMissing: "初始化卡住:core.js 没有加载(检查 /vrmpet3d/window/lib/core.js 是否 404)。",
|
|
194
|
+
stuck: "初始化卡住:脚本已加载但没有完成初始化(看看窗口的控制台,或宿主是否提供 /vrmpet3d/settings)。",
|
|
195
|
+
}
|
|
196
|
+
: {
|
|
197
|
+
error: "Page script error: ",
|
|
198
|
+
file: "(from {name})",
|
|
199
|
+
coreMissing: "Stuck at startup: core.js did not load (check whether /vrmpet3d/window/lib/core.js is a 404).",
|
|
200
|
+
stuck: "Stuck at startup: the script loaded but never finished initialising (check the window console, or whether the host serves /vrmpet3d/settings).",
|
|
201
|
+
};
|
|
174
202
|
function show(message) {
|
|
175
203
|
var status = document.getElementById("status");
|
|
176
204
|
if (status) { status.textContent = message; status.className = "warn"; }
|
|
177
205
|
}
|
|
178
206
|
window.addEventListener("error", function (event) {
|
|
179
|
-
show(
|
|
207
|
+
show(WORDS.error + (event.message || event.type)
|
|
208
|
+
+ (event.filename ? " " + WORDS.file.replace("{name}", event.filename) : ""));
|
|
180
209
|
}, true);
|
|
181
210
|
window.setTimeout(function () {
|
|
182
211
|
if (window.__VRMPET3D_CONFIG_STATE__) return;
|
|
183
|
-
if (!window.__VRMPET3D_CORE__) {
|
|
184
|
-
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
show("初始化卡住:脚本已加载但没有完成初始化(看看窗口的控制台,或宿主是否提供 /vrmpet3d/settings)。");
|
|
212
|
+
if (!window.__VRMPET3D_CORE__) { show(WORDS.coreMissing); return; }
|
|
213
|
+
show(WORDS.stuck);
|
|
188
214
|
}, 2000);
|
|
189
215
|
})();
|
|
190
216
|
</script>
|