@ganziliang/desktop-pet 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 CHANGED
@@ -24,6 +24,7 @@ desktop-pet
24
24
  ```
25
25
 
26
26
  包内自带 electron 依赖,命令行参数原样透传给主进程(`--snapshot`、`--anim=<walk|run|swim|awaken:seraph>`、`--no-auto`)。
27
+ 首次启动会先下载 Electron 运行时(约 100MB,只在第一次),终端会打印 `Downloading Electron binary...`。
27
28
  只发布运行需要的素材,`assets/source/`(生图原始图,约 39MB)与 `character_green*.png` 不进包。
28
29
 
29
30
 
@@ -59,21 +60,29 @@ desktop-pet
59
60
  和特效事件共用同一条时间轴,所以「动作推到哪一帧」和「特效炸在哪一刻」是对死的:
60
61
 
61
62
  ```
62
- 0ms 黑屏切入(canvas 暗幕,全黑 0.94)
63
- 180ms 窗口放大(藏在黑幕里,看不见窗口在变形)
64
- 560ms 暗幕提到 0.6 —— 角色以「蓄力」序列帧亮相
63
+ 0ms 切入(默认不铺暗幕,桌面直接透出去)
64
+ 180ms 窗口放大(只向上、向两侧长,脚下那条线和水平中心都不动,所以看不到变形)
65
+ 560ms 角色以「蓄力」序列帧亮相
65
66
  蓄力 4 帧 × 360ms:合手聚气 → 抬手 → 上举 → 蓄力顶点
66
67
  同时跑魔法阵、向心汇聚、脚下螺旋
67
68
  2000ms 爆发(revealAt):白闪 + 抖屏 + 冲击波,切到「爆发」序列帧
68
69
  爆发 4 帧 × 300ms:张臂 → 光爆 → 释放 → 收势
69
70
  2200ms 光柱冲天 + 主爆星屑
70
71
  2650ms 技能名落字
71
- 4400ms 暗幕再进 + 窗口收回(同样藏在黑幕里)
72
- 5700ms 暗幕退掉,回到站立
72
+ 4400ms 窗口收回(同样只向上向两侧收,角色不动)
73
+ 5700ms 回到站立
73
74
  ```
74
75
 
75
- 暗幕在 `charge.at` 就从全黑提到 0.6,所以**蓄力动作是真的看得见的** ——
76
- 不是一层黑幕盖满五秒再炸一下。
76
+ **演出期间窗口背景完全透明**:桌面上只看得到角色和光效,不会出现一块暗色矩形。
77
+ 这一点靠 `assets/outfits.json` 的 `curtain` 控制,默认 `false`:
78
+
79
+ ```json
80
+ { "curtain": false }
81
+ ```
82
+
83
+ 要不要铺暗幕,取决于壁纸:加色混合的光效(金光、雷光)在**亮色壁纸**上本来就很难拉开对比,
84
+ 垫一层暗底才亮得起来 —— 想回到老的「黑屏切入」就把 `curtain` 改成 `true`(代价是屏幕上会多一个暗窗)。
85
+ 关掉时光效照跑,只是没有暗底垫着。
77
86
 
78
87
  ### 素材是两步,不是一步
79
88
 
@@ -315,7 +324,7 @@ npx electron . --snapshot
315
324
  # --anim=<walk|run|swim> 先把角色摆到某个动作再截,用来查动作素材
316
325
  npx electron . --snapshot --anim=swim
317
326
  # 觉醒也能截:--anim=awaken:<id>;换 PET_SNAPSHOT_MS 就能逐帧看整场演出
318
- PET_SNAPSHOT_MS=1200 npx electron . --snapshot --anim=awaken:seraph # 蓄力:黑屏 + 魔法阵
327
+ PET_SNAPSHOT_MS=1200 npx electron . --snapshot --anim=awaken:seraph # 蓄力:魔法阵 + 聚气
319
328
  PET_SNAPSHOT_MS=3400 npx electron . --snapshot --anim=awaken:seraph # 亮相 + 技能名
320
329
  PET_SNAPSHOT_MS=6500 npx electron . --snapshot --anim=awaken:seraph # 收招:窗口应该已还原
321
330
  # PET_SNAPSHOT_MS 改截帧时刻。用两个不同值各截一张做差分,就能证明逐帧动画真的在推进:
@@ -18,11 +18,12 @@
18
18
  ```js
19
19
  sheet: { charge: { at: 560, step: 360 }, burst: { at: 2000, step: 300 } },
20
20
  revealAt: 2000, // = burst.at,爆发那一刻(白闪 + 抖屏)
21
- closeAt: 4400, // 暗幕再进 + 窗口收回
21
+ closeAt: 4400, // 窗口收回(默认铺暗幕;见下)
22
22
  ```
23
23
 
24
24
  蓄力 4 帧 × 360ms(560→1640),爆发 4 帧 × 300ms(2000→2900),之后停在最后一帧收招式。
25
- 暗幕在 `charge.at` 从全黑提到 0.6,所以**蓄力动作是真的看得见的**,不是一层黑幕盖完五秒。
25
+ 暗幕默认**关**(`assets/outfits.json` `curtain: false`):演出期间窗口背景全透明,墙上不会出现暗色矩形。
26
+ 改成 `true` 就回到「黑屏切入」—— 起步全黑、`charge.at` 提到 0.6 的柔暗底,蓄力动作依然看得见。
26
27
 
27
28
  ## 怎么加一张
28
29
 
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "comment": "战斗服装 / 觉醒技能清单。渲染层按 id 找 assets/awaken/<id>.png 作为觉醒立绘;素材缺失时用 idle 帧 + 纯特效兜底,不会崩。",
3
+ "curtain": false,
3
4
  "stage": {
4
5
  "widthRatio": 0.46,
5
6
  "heightRatio": 0.72,
package/main.js CHANGED
@@ -128,12 +128,20 @@ function loadSpriteManifest() {
128
128
  * 而不会因为少个 json 让整个右键菜单空掉。
129
129
  */
130
130
  function loadOutfits() {
131
- const fallback = { stage: {}, list: [{ id: 'seraph', name: '圣光 · 炽天使', skill: '圣裁之光' }] };
131
+ const fallback = {
132
+ stage: {},
133
+ list: [{ id: 'seraph', name: '圣光 · 炽天使', skill: '圣裁之光' }],
134
+ curtain: false,
135
+ };
132
136
  try {
133
137
  const raw = JSON.parse(fs.readFileSync(OUTFITS_FILE, 'utf8'));
134
138
  return {
135
139
  stage: raw.stage || {},
136
140
  list: Array.isArray(raw.list) && raw.list.length ? raw.list : fallback.list,
141
+ // 觉醒暗幕开关。默认关:演出期间窗口背景完全透明,桌面上只有角色和光效,
142
+ // 不会出现一块暗色矩形。显式写 true 才回到旧的「黑屏切入」
143
+ // (亮色壁纸下加色光效更清楚,代价是屏幕上多一个暗窗)。
144
+ curtain: raw.curtain === true,
137
145
  };
138
146
  } catch {
139
147
  return fallback;
@@ -1002,7 +1010,7 @@ function registerIpc() {
1002
1010
  roamGapMs: Number(process.env.PET_ROAM_GAP_MS) || null,
1003
1011
  assets: spriteAssets(),
1004
1012
  // 觉醒清单交给渲染层:菜单里的名字、角色缩放比例、窗口目标规模都从这取
1005
- awaken: { list: outfits.list, stage: outfits.stage },
1013
+ awaken: { list: outfits.list, stage: outfits.stage, curtain: outfits.curtain },
1006
1014
  httpPort: HTTP_PORT,
1007
1015
  }));
1008
1016
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganziliang/desktop-pet",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "桌面动漫角色小控件:透明置顶窗 + 像素级命中测试 + 鼠标交互 + 本地 HTTP 消息接口(Electron 桌宠)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/renderer/app.js CHANGED
@@ -716,18 +716,28 @@ function applyDemo(anim) {
716
716
 
717
717
  /**
718
718
  * 一场觉醒演出的时间线(毫秒):
719
- * 0 黑屏切入(canvas 暗幕)
719
+ * 0 切入(curtain=true 时是黑屏,默认直接把桌面透出去)
720
720
  * 180 窗口放大 + 换上战斗服立绘 + 「镜头推近」
721
- * revealAt 暗幕退 + 白闪 + 画面抖动 + 主爆发(具体特效由各套觉醒的 build 排)
722
- * closeAt 暗幕再进 + 窗口收回(正好盖住窗口变回去的那一帧)
721
+ * revealAt 亮相 + 白闪 + 画面抖动 + 主爆发(具体特效由各套觉醒的 build 排)
722
+ * closeAt 暗幕再进 + 窗口收回
723
723
  * duration 暗幕退掉,回到站立
724
724
  *
725
- * 关键点:窗口尺寸是在「暗幕已经盖满」之后才改的,所以看不到窗口在变形。
726
- * DNF 的觉醒也是这么处理的 —— 黑屏切入从来不只是省钱,它负责把不好看的那一帧藏起来。
725
+ * 窗口尺寸是在「画面已经被盖住」之后才改的。默认 curtain=false,也就是不铺暗幕:
726
+ * 窗口只向上、向两侧长(见 main.js awakenTarget),角色脚下那条线和水平中心都不动,
727
+ * 所以窗口变形这一帧本来就看不出来 —— 没必要为了藏它而多一块暗色矩形。
728
+ * 亮色壁纸下想让金光/雷光更亮,可以在 assets/outfits.json 里把 curtain 改成 true。
727
729
  */
728
730
 
729
731
  let awakenToken = 0; // 每次演出一个令牌;旧演出的挂起回调拿它对不上号就自己失效
730
732
 
733
+ /**
734
+ * 暗幕开关(assets/outfits.json 的 curtain,默认 false = 不铺暗色底)。
735
+ * 关掉时所有 dim 的 alpha 都走 0:FX 那套渐变/时间轴一行不用改,
736
+ * 只是每帧的 drawDim 直接 return,画布上除角色和光效之外没有别的东西。
737
+ */
738
+ const curtainOn = () => cfg.awaken?.curtain === true;
739
+ const curtainAlpha = (a) => (curtainOn() ? a : 0);
740
+
731
741
  /** 角色当前的屏幕位置,事件在触发的那一刻现取(窗口刚被放大过) */
732
742
  /**
733
743
  * 觉醒演出的逐帧播放:直接写 backgroundPositionX,不走 steps() 帧动画。
@@ -806,8 +816,8 @@ async function playAwaken(id, { auto = false } = {}) {
806
816
  }
807
817
  holdShow();
808
818
 
809
- // 1) 先把屏幕压黑
810
- FX.dim(def.dimAlpha, 170, def.palette.stroke);
819
+ // 1) 先把屏幕压黑(curtain=false 时是 0,等于什么都不铺)
820
+ FX.dim(curtainAlpha(def.dimAlpha), 170, def.palette.stroke);
811
821
 
812
822
  // 2) 暗幕盖满之后再把窗口放大,同时按新窗口高度算「镜头推近」的倍数
813
823
  await new Promise((r) => setTimeout(r, 180));
@@ -858,7 +868,8 @@ async function playAwaken(id, { auto = false } = {}) {
858
868
 
859
869
  // 蓄力:暗幕从全黑提到 0.6(soft),让玩家真的能看到蓄力动作在演,
860
870
  // 而不是从头到尾一层黑幕摆完五秒 —— 那多帧素材就白做了。
861
- if (sheet.charge) {
871
+ // curtain=false 时这层不铺:桌面本来就透得出来,角色一直看得见。
872
+ if (sheet.charge && curtainOn()) {
862
873
  events.push([sheet.charge.at, () => FX.dim(0.6, 420, def.palette.stroke, true)]);
863
874
  }
864
875
 
@@ -885,8 +896,9 @@ async function playAwaken(id, { auto = false } = {}) {
885
896
  def.closeAt,
886
897
  () => {
887
898
  if (token !== awakenToken) return;
888
- FX.dim(def.dimAlpha, 240, def.palette.stroke);
889
- // 窗口变回去这一帧同样藏在暗幕后面,所以这里可以放心地提前收
899
+ FX.dim(curtainAlpha(def.dimAlpha), 240, def.palette.stroke);
900
+ // 窗口变回去的那一帧本来就不用遮(窗口只向上向两侧收回,角色不动),
901
+ // 这里留着只是让 curtain=true 的旧路径一样安全
890
902
  setTimeout(() => {
891
903
  if (token !== awakenToken) return;
892
904
  el.stage.classList.remove('awakening', 'flashing', 'shaking');