dsh-wisp 0.6.0 → 1.25.0
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 +869 -10
- package/assets/canon/attn.webp +0 -0
- package/assets/canon/happy.webp +0 -0
- package/assets/canon/idle.webp +0 -0
- package/assets/canon/poked.webp +0 -0
- package/assets/canon/proud.webp +0 -0
- package/assets/canon/sleepy.webp +0 -0
- package/assets/canon/work.webp +0 -0
- package/assets/classic/attn.webp +0 -0
- package/assets/classic/happy.webp +0 -0
- package/assets/classic/idle.webp +0 -0
- package/assets/classic/poked.webp +0 -0
- package/assets/classic/proud.webp +0 -0
- package/assets/classic/sleepy.webp +0 -0
- package/assets/classic/work.webp +0 -0
- package/assets/deepsea/attn.webp +0 -0
- package/assets/deepsea/happy.webp +0 -0
- package/assets/deepsea/idle.webp +0 -0
- package/assets/deepsea/poked.webp +0 -0
- package/assets/deepsea/proud.webp +0 -0
- package/assets/deepsea/sleepy.webp +0 -0
- package/assets/deepsea/work.webp +0 -0
- package/assets/night/attn.webp +0 -0
- package/assets/night/happy.webp +0 -0
- package/assets/night/idle.webp +0 -0
- package/assets/night/poked.webp +0 -0
- package/assets/night/proud.webp +0 -0
- package/assets/night/sleepy.webp +0 -0
- package/assets/night/work.webp +0 -0
- package/assets/pajama/attn.webp +0 -0
- package/assets/pajama/happy.webp +0 -0
- package/assets/pajama/idle.webp +0 -0
- package/assets/pajama/poked.webp +0 -0
- package/assets/pajama/proud.webp +0 -0
- package/assets/pajama/sleepy.webp +0 -0
- package/assets/pajama/work.webp +0 -0
- package/audit/generation-audit.jsonl +35 -0
- package/build.mjs +93 -30
- package/cordis.patch.yml +2 -0
- package/lib/client.js +1292 -41
- package/lib/client.template.js +1247 -37
- package/lib/index.js +115 -12
- package/package.json +8 -1
- package/tools/CHARACTER-PROMPT.md +221 -3
- package/tools/assets.mjs +39 -16
- package/tools/audit-log.mjs +245 -0
- package/tools/bundle-cost.mjs +105 -0
- package/tools/pack-check.mjs +78 -0
- package/tools/perf.mjs +186 -0
- package/tools/smoke.mjs +577 -0
- package/tools/tiers.mjs +104 -0
- package/verify-wisp.mjs +2681 -872
- package/assets/happy.webp +0 -0
- package/assets/happy_hi.webp +0 -0
- package/assets/happy_md.webp +0 -0
- package/assets/happy_sm.webp +0 -0
- package/assets/idle.webp +0 -0
- package/assets/idle_hi.webp +0 -0
- package/assets/idle_md.webp +0 -0
- package/assets/idle_sm.webp +0 -0
- package/assets/sleepy.webp +0 -0
- package/assets/sleepy_hi.webp +0 -0
- package/assets/sleepy_md.webp +0 -0
- package/assets/sleepy_sm.webp +0 -0
- package/assets/work.webp +0 -0
- package/assets/work_hi.webp +0 -0
- package/assets/work_md.webp +0 -0
- package/assets/work_sm.webp +0 -0
package/tools/tiers.mjs
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
tiers.mjs — 把「已经抠好的透明 PNG」分成四档素材。
|
|
3
|
+
|
|
4
|
+
与 assets.mjs 的分工:
|
|
5
|
+
assets.mjs 绿幕母版 → 抠图 → 四档 (一次做完)
|
|
6
|
+
tiers.mjs 已抠好的透明 PNG → 四档 (不重复抠图)
|
|
7
|
+
|
|
8
|
+
什么时候用这个:母版是抠过的成品、或者绿幕原图已经不在了。**不要**把已经抠过的
|
|
9
|
+
图再喂给 assets.mjs —— 那会二次抠图,结果依赖"透明像素里是否还残留绿色"。
|
|
10
|
+
抠图是幂等的假象,不是保证。
|
|
11
|
+
|
|
12
|
+
RUN
|
|
13
|
+
node tools/tiers.mjs --from <透明PNG目录> --skin <皮肤名>
|
|
14
|
+
node tools/tiers.mjs --from ./keyed --skin deepsea
|
|
15
|
+
========================================================================== */
|
|
16
|
+
|
|
17
|
+
import { existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'
|
|
18
|
+
import { createRequire } from 'node:module'
|
|
19
|
+
import { dirname, join, resolve } from 'node:path'
|
|
20
|
+
import { fileURLToPath } from 'node:url'
|
|
21
|
+
|
|
22
|
+
const here = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
23
|
+
const require = createRequire(import.meta.url)
|
|
24
|
+
|
|
25
|
+
function loadSharp() {
|
|
26
|
+
const dir = process.env.DSH_PROFILE_DIR
|
|
27
|
+
const candidates = [
|
|
28
|
+
process.env.WISP_SHARP,
|
|
29
|
+
dir ? join(dir, '..', 'node_modules', 'sharp') : null,
|
|
30
|
+
'sharp',
|
|
31
|
+
].filter(Boolean)
|
|
32
|
+
for (const c of candidates) {
|
|
33
|
+
try { return require(c) } catch (e) { /* 试下一个 */ }
|
|
34
|
+
}
|
|
35
|
+
throw new Error('找不到 sharp:请设置环境变量 WISP_SHARP 指向 sharp 包目录')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const argv = process.argv.slice(2)
|
|
39
|
+
/* 默认只写第一档(会进包的那一档);--all-tiers 才写全部四档。 */
|
|
40
|
+
const allTiers = argv.includes('--all-tiers')
|
|
41
|
+
const flag = (name, fallback) => {
|
|
42
|
+
const at = argv.indexOf(name)
|
|
43
|
+
return at >= 0 && argv[at + 1] !== undefined ? argv[at + 1] : fallback
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const MOODS = ['idle', 'happy', 'sleepy', 'work', 'attn']
|
|
47
|
+
/* 同 tools/assets.mjs:默认只写会进包的那一档,其余要 --all-tiers。 */
|
|
48
|
+
const ALL_TIERS = [
|
|
49
|
+
{ suffix: '', w: 1024, q: 84 },
|
|
50
|
+
{ suffix: '_md', w: 512, q: 82 },
|
|
51
|
+
{ suffix: '_sm', w: 256, q: 80 },
|
|
52
|
+
{ suffix: '_hi', w: 2048, q: 86 },
|
|
53
|
+
]
|
|
54
|
+
/* 选择语句必须**在数组定义之后**:放在前面会踩 TDZ(Cannot access before initialization)。 */
|
|
55
|
+
const TIERS = allTiers ? ALL_TIERS : ALL_TIERS.slice(0, 1)
|
|
56
|
+
|
|
57
|
+
const srcDir = resolve(here, flag('--from', 'keyed'))
|
|
58
|
+
const skin = flag('--skin', '')
|
|
59
|
+
if (skin === '') {
|
|
60
|
+
console.error('用法: node tools/tiers.mjs --from <透明PNG目录> --skin <皮肤名>')
|
|
61
|
+
process.exit(1)
|
|
62
|
+
}
|
|
63
|
+
const outDir = resolve(here, flag('--out', join('assets', skin)))
|
|
64
|
+
|
|
65
|
+
if (!existsSync(srcDir)) {
|
|
66
|
+
console.error(`母版目录不存在: ${srcDir}`)
|
|
67
|
+
process.exit(1)
|
|
68
|
+
}
|
|
69
|
+
const available = new Set(readdirSync(srcDir).map((f) => f.replace(/\.png$/i, '')))
|
|
70
|
+
const missing = MOODS.filter((m) => !available.has(m))
|
|
71
|
+
if (missing.length > 0) {
|
|
72
|
+
console.error(`缺少已抠母版: ${missing.map((m) => m + '.png').join(', ')}(在 ${srcDir})`)
|
|
73
|
+
process.exit(1)
|
|
74
|
+
}
|
|
75
|
+
mkdirSync(outDir, { recursive: true })
|
|
76
|
+
|
|
77
|
+
const sharp = loadSharp()
|
|
78
|
+
console.log(`已抠母版: ${srcDir}\n输出: ${outDir}\n`)
|
|
79
|
+
console.log('mood 源尺寸 四档')
|
|
80
|
+
|
|
81
|
+
let total = 0
|
|
82
|
+
for (const mood of MOODS) {
|
|
83
|
+
const src = join(srcDir, `${mood}.png`)
|
|
84
|
+
const meta = await sharp(src).metadata()
|
|
85
|
+
if (!meta.hasAlpha) {
|
|
86
|
+
// 没有 alpha 说明它根本不是抠过的图 —— 分档会得到带底色的素材,必须拦住
|
|
87
|
+
console.error(` ${mood}: 没有 alpha 通道,这不是抠好的图(该走 tools/assets.mjs)`)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
const sizes = []
|
|
91
|
+
for (const tier of TIERS) {
|
|
92
|
+
const out = join(outDir, `${mood}${tier.suffix}.webp`)
|
|
93
|
+
await sharp(src)
|
|
94
|
+
.resize(tier.w, Math.round(tier.w * 1.5), { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
|
95
|
+
.webp({ quality: tier.q, alphaQuality: 92, effort: 6 })
|
|
96
|
+
.toFile(out)
|
|
97
|
+
sizes.push(`${tier.suffix || '默认'} ${Math.round(statSync(out).size / 1024)}KB`)
|
|
98
|
+
total += statSync(out).size
|
|
99
|
+
}
|
|
100
|
+
console.log(` ${mood.padEnd(7)} ${String(meta.width + 'x' + meta.height).padEnd(11)} ${sizes.join(' ')}`)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(`\n共 ${(total / 1024).toFixed(0)} KB(四档 × ${MOODS.length} 情绪)`)
|
|
104
|
+
console.log('接着跑 `node build.mjs`(默认用「默认」档;要 4K 档加 --tier=hi)。')
|