mocode-pet-app 1.4.0 → 1.7.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.
Files changed (89) hide show
  1. package/assets/pets/01-robo-cat.motion.css +42 -0
  2. package/assets/pets/01-robo-cat.svg +2 -2
  3. package/assets/pets/02-robo-dog.motion.css +42 -0
  4. package/assets/pets/02-robo-dog.svg +1 -1
  5. package/assets/pets/03-robo-fox.motion.css +63 -0
  6. package/assets/pets/03-robo-fox.svg +1 -1
  7. package/assets/pets/04-robo-panda.motion.css +61 -0
  8. package/assets/pets/04-robo-panda.svg +1 -1
  9. package/assets/pets/05-robo-owl.motion.css +88 -0
  10. package/assets/pets/05-robo-owl.svg +3 -3
  11. package/assets/pets/06-robo-bunny.motion.css +84 -0
  12. package/assets/pets/06-robo-bunny.svg +2 -2
  13. package/assets/pets/07-robo-frog.motion.css +65 -0
  14. package/assets/pets/07-robo-frog.svg +3 -3
  15. package/assets/pets/08-robo-bear.motion.css +65 -0
  16. package/assets/pets/09-robo-penguin.motion.css +94 -0
  17. package/assets/pets/09-robo-penguin.svg +3 -3
  18. package/assets/pets/10-robo-dino.motion.css +91 -0
  19. package/assets/pets/10-robo-dino.svg +3 -3
  20. package/assets/pets/11-slime-blob.motion.css +44 -0
  21. package/assets/pets/11-slime-blob.svg +3 -3
  22. package/assets/pets/12-ghost-byte.motion.css +73 -0
  23. package/assets/pets/12-ghost-byte.svg +3 -3
  24. package/assets/pets/13-cactus-bot.motion.css +90 -0
  25. package/assets/pets/13-cactus-bot.svg +2 -2
  26. package/assets/pets/14-crystal-bot.motion.css +63 -0
  27. package/assets/pets/15-satellite-bot.motion.css +72 -0
  28. package/assets/pets/15-satellite-bot.svg +1 -1
  29. package/assets/pets/16-jellyfish-bot.motion.css +71 -0
  30. package/assets/pets/16-jellyfish-bot.svg +3 -3
  31. package/assets/pets/17-mushroom-bot.motion.css +65 -0
  32. package/assets/pets/18-star-bot.motion.css +72 -0
  33. package/assets/pets/18-star-bot.svg +3 -3
  34. package/assets/pets/manifest.json +139 -25
  35. package/dist/assets/pets/01-robo-cat.motion.css +42 -0
  36. package/dist/assets/pets/01-robo-cat.svg +2 -2
  37. package/dist/assets/pets/02-robo-dog.motion.css +42 -0
  38. package/dist/assets/pets/02-robo-dog.svg +1 -1
  39. package/dist/assets/pets/03-robo-fox.motion.css +63 -0
  40. package/dist/assets/pets/03-robo-fox.svg +1 -1
  41. package/dist/assets/pets/04-robo-panda.motion.css +61 -0
  42. package/dist/assets/pets/04-robo-panda.svg +1 -1
  43. package/dist/assets/pets/05-robo-owl.motion.css +88 -0
  44. package/dist/assets/pets/05-robo-owl.svg +3 -3
  45. package/dist/assets/pets/06-robo-bunny.motion.css +84 -0
  46. package/dist/assets/pets/06-robo-bunny.svg +2 -2
  47. package/dist/assets/pets/07-robo-frog.motion.css +65 -0
  48. package/dist/assets/pets/07-robo-frog.svg +3 -3
  49. package/dist/assets/pets/08-robo-bear.motion.css +65 -0
  50. package/dist/assets/pets/09-robo-penguin.motion.css +94 -0
  51. package/dist/assets/pets/09-robo-penguin.svg +3 -3
  52. package/dist/assets/pets/10-robo-dino.motion.css +91 -0
  53. package/dist/assets/pets/10-robo-dino.svg +3 -3
  54. package/dist/assets/pets/11-slime-blob.motion.css +44 -0
  55. package/dist/assets/pets/11-slime-blob.svg +3 -3
  56. package/dist/assets/pets/12-ghost-byte.motion.css +73 -0
  57. package/dist/assets/pets/12-ghost-byte.svg +3 -3
  58. package/dist/assets/pets/13-cactus-bot.motion.css +90 -0
  59. package/dist/assets/pets/13-cactus-bot.svg +2 -2
  60. package/dist/assets/pets/14-crystal-bot.motion.css +63 -0
  61. package/dist/assets/pets/15-satellite-bot.motion.css +72 -0
  62. package/dist/assets/pets/15-satellite-bot.svg +1 -1
  63. package/dist/assets/pets/16-jellyfish-bot.motion.css +71 -0
  64. package/dist/assets/pets/16-jellyfish-bot.svg +3 -3
  65. package/dist/assets/pets/17-mushroom-bot.motion.css +65 -0
  66. package/dist/assets/pets/18-star-bot.motion.css +72 -0
  67. package/dist/assets/pets/18-star-bot.svg +3 -3
  68. package/dist/assets/pets/manifest.json +139 -25
  69. package/dist/assets/tray-icon.png +0 -0
  70. package/dist/e2e-mood-check.js +150 -0
  71. package/dist/main.js +53 -2
  72. package/dist/mood-current-state.test.js +55 -0
  73. package/dist/mood-determinism.pbt.js +66 -0
  74. package/dist/mood-tracker-timing.test.js +70 -0
  75. package/dist/mood-tracker.js +41 -0
  76. package/dist/mood-tracker.test.js +56 -0
  77. package/dist/mood.js +102 -0
  78. package/dist/mood.pbt.js +52 -0
  79. package/dist/quips.js +59 -0
  80. package/dist/quips.test.js +98 -0
  81. package/dist/renderer/dom-mood.js +55 -0
  82. package/dist/renderer/dom-mood.test.js +105 -0
  83. package/dist/renderer/index.html +2 -0
  84. package/dist/renderer/preload.js +20 -2
  85. package/dist/renderer/renderer.js +29 -9
  86. package/dist/renderer/style.css +89 -0
  87. package/dist/skins.js +50 -1
  88. package/dist/skins.test.js +112 -0
  89. package/package.json +1 -1
@@ -0,0 +1,94 @@
1
+ /* 机械企鹅(robo-penguin)专属演出:体现"企鹅"的摇摆与笨拙,所有动作以"左右晃"为核心。
2
+ * #pet-arm-left/right 是扁平鳍翼,这里当作鳍状手臂处理;pet-mouth 是橙色喙。 */
3
+
4
+ /* ── thinking:鳍翼小幅度拍打 + 身体轻摇 ── */
5
+ @keyframes penguin-think-flipper-left {
6
+ 0%, 100% { transform: rotate(0deg); }
7
+ 50% { transform: rotate(-10deg); }
8
+ }
9
+ @keyframes penguin-think-flipper-right {
10
+ 0%, 100% { transform: rotate(0deg); }
11
+ 50% { transform: rotate(10deg); }
12
+ }
13
+ .pet-thinking #pet-arm-left {
14
+ animation: penguin-think-flipper-left 0.9s ease-in-out infinite;
15
+ transform-origin: 42px 170px;
16
+ }
17
+ .pet-thinking #pet-arm-right {
18
+ animation: penguin-think-flipper-right 0.9s ease-in-out infinite 0.45s;
19
+ transform-origin: 214px 170px;
20
+ }
21
+
22
+ /* ── idle:站着轻微左右晃 ── */
23
+ @keyframes penguin-idle-wobble {
24
+ 0%, 100% { transform: rotate(0deg); }
25
+ 50% { transform: rotate(3deg); }
26
+ }
27
+ .pet-idle #pet-body-group {
28
+ animation: penguin-idle-wobble 2.2s ease-in-out infinite;
29
+ transform-origin: 128px 230px;
30
+ }
31
+
32
+ /* ── tool_call:企鹅招牌的左右摇摆(代替双臂摆动) + 鳍翼配合 ── */
33
+ @keyframes penguin-tool-waddle {
34
+ 0%, 100% { transform: rotate(0deg); }
35
+ 25% { transform: rotate(-7deg); }
36
+ 75% { transform: rotate(7deg); }
37
+ }
38
+ @keyframes penguin-tool-flipper-left {
39
+ 0%, 100% { transform: rotate(0deg); }
40
+ 50% { transform: rotate(-18deg); }
41
+ }
42
+ @keyframes penguin-tool-flipper-right {
43
+ 0%, 100% { transform: rotate(0deg); }
44
+ 50% { transform: rotate(18deg); }
45
+ }
46
+ .pet-tool #pet-body-group {
47
+ animation: penguin-tool-waddle 0.55s ease-in-out infinite;
48
+ transform-origin: 128px 230px;
49
+ }
50
+ .pet-tool #pet-arm-left {
51
+ animation: penguin-tool-flipper-left 0.55s ease-in-out infinite;
52
+ transform-origin: 42px 170px;
53
+ }
54
+ .pet-tool #pet-arm-right {
55
+ animation: penguin-tool-flipper-right 0.55s ease-in-out infinite 0.27s;
56
+ transform-origin: 214px 170px;
57
+ }
58
+
59
+ /* ── mood-urging:急促的鳍翼拍打 + 嘴部(喙)开合催促 ── */
60
+ @keyframes penguin-urging-flipper-left {
61
+ 0%, 100% { transform: rotate(0deg); }
62
+ 50% { transform: rotate(-22deg); }
63
+ }
64
+ @keyframes penguin-urging-flipper-right {
65
+ 0%, 100% { transform: rotate(0deg); }
66
+ 50% { transform: rotate(22deg); }
67
+ }
68
+ @keyframes penguin-urging-beak {
69
+ 0%, 100% { transform: scaleY(1); }
70
+ 50% { transform: scaleY(1.5); }
71
+ }
72
+ .mood-urging #pet-arm-left {
73
+ animation: penguin-urging-flipper-left 0.18s ease-in-out infinite;
74
+ transform-origin: 42px 170px;
75
+ }
76
+ .mood-urging #pet-arm-right {
77
+ animation: penguin-urging-flipper-right 0.18s ease-in-out infinite 0.09s;
78
+ transform-origin: 214px 170px;
79
+ }
80
+ .mood-urging #pet-mouth {
81
+ animation: penguin-urging-beak 0.18s ease-in-out infinite;
82
+ transform-origin: 128px 156px;
83
+ }
84
+
85
+ /* ── done:小滑步式的弹跳 ── */
86
+ @keyframes penguin-done-slide {
87
+ 0% { transform: translateX(0) scale(1); }
88
+ 40% { transform: translateX(0) scale(1.08); }
89
+ 100% { transform: translateX(0) scale(1); }
90
+ }
91
+ .pet-done #pet-body-group {
92
+ animation: penguin-done-slide 0.45s ease-out 1;
93
+ transform-origin: 128px 230px;
94
+ }
@@ -36,11 +36,11 @@
36
36
  </g>
37
37
 
38
38
  <!-- Beak -->
39
- <path d="M116 156 L128 172 L140 156 Z" fill="#ffb74d"/>
39
+ <path id="pet-mouth" d="M116 156 L128 172 L140 156 Z" fill="#ffb74d"/>
40
40
 
41
41
  <!-- Flipper arms(填充块面而非线条,贴身收成圆润小翼) -->
42
- <path d="M42 146 Q16 162 22 190 Q26 204 42 202 Q50 200 46 188 Q40 168 46 150 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2"/>
43
- <path d="M214 146 Q240 162 234 190 Q230 204 214 202 Q206 200 210 188 Q216 168 210 150 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2"/>
42
+ <path id="pet-arm-left" d="M42 146 Q16 162 22 190 Q26 204 42 202 Q50 200 46 188 Q40 168 46 150 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2"/>
43
+ <path id="pet-arm-right" d="M214 146 Q240 162 234 190 Q230 204 214 202 Q206 200 210 188 Q216 168 210 150 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2"/>
44
44
 
45
45
  <!-- Feet -->
46
46
  <ellipse cx="104" cy="234" rx="16" ry="8" fill="#ffb74d"/>
@@ -0,0 +1,91 @@
1
+ /* 机械龙(robo-dino)专属演出:体现"小龙"的凶猛与小只的暴躁,动作短促、节奏快、幅度大。
2
+ * #pet-arm-left/right 是两只小短手,只能用 rotate 模拟拍打;
3
+ * 嘴部 (#pet-mouth) 是锯齿状,适合用 scaleY 模拟咬合。 */
4
+
5
+ /* ── thinking:上下颌咬合(嘴部张合,模拟正在思考时"哼"的表情) ── */
6
+ @keyframes dino-think-jaw {
7
+ 0%, 100% { transform: scaleY(1); }
8
+ 50% { transform: scaleY(1.7); }
9
+ }
10
+ .pet-thinking #pet-mouth {
11
+ animation: dino-think-jaw 0.5s ease-in-out infinite;
12
+ transform-origin: 128px 148px;
13
+ }
14
+
15
+ /* ── idle:小幅度来回甩头(像小恐龙好动) ── */
16
+ @keyframes dino-idle-shake {
17
+ 0%, 100% { transform: rotate(0deg); }
18
+ 25% { transform: rotate(-3deg); }
19
+ 75% { transform: rotate(3deg); }
20
+ }
21
+ .pet-idle #pet-body-group {
22
+ animation: dino-idle-shake 1.8s ease-in-out infinite;
23
+ transform-origin: 128px 125px;
24
+ }
25
+
26
+ /* ── tool_call:小短手快速拍打 + 嘴部跟随咬合 ── */
27
+ @keyframes dino-tool-arm-left {
28
+ 0%, 100% { transform: rotate(-34deg); }
29
+ 50% { transform: rotate(-65deg); }
30
+ }
31
+ @keyframes dino-tool-arm-right {
32
+ 0%, 100% { transform: rotate(34deg); }
33
+ 50% { transform: rotate(65deg); }
34
+ }
35
+ @keyframes dino-tool-jaw {
36
+ 0%, 100% { transform: scaleY(1); }
37
+ 50% { transform: scaleY(1.4); }
38
+ }
39
+ .pet-tool #pet-arm-left {
40
+ animation: dino-tool-arm-left 0.25s ease-in-out infinite;
41
+ transform-origin: 31px 142px;
42
+ }
43
+ .pet-tool #pet-arm-right {
44
+ animation: dino-tool-arm-right 0.25s ease-in-out infinite 0.12s;
45
+ transform-origin: 223px 142px;
46
+ }
47
+ .pet-tool #pet-mouth {
48
+ animation: dino-tool-jaw 0.25s ease-in-out infinite;
49
+ transform-origin: 128px 148px;
50
+ }
51
+
52
+ /* ── mood-frustrated:暴躁甩头(替换通用 0.15s 平移抖动为更"角色化"的旋转甩头) ── */
53
+ @keyframes dino-frustrated-slam {
54
+ 0%, 100% { transform: rotate(0deg) translateX(0); }
55
+ 20% { transform: rotate(-6deg) translateX(-4px); }
56
+ 60% { transform: rotate(6deg) translateX(4px); }
57
+ }
58
+ .mood-frustrated #pet-body-group {
59
+ animation: dino-frustrated-slam 0.18s ease-in-out infinite;
60
+ transform-origin: 128px 125px;
61
+ }
62
+
63
+ /* ── mood-urging:急躁跺脚 ── */
64
+ @keyframes dino-urging-stomp {
65
+ 0%, 100% { transform: translateY(0) rotate(0deg); }
66
+ 50% { transform: translateY(0) rotate(-5deg); }
67
+ }
68
+ @keyframes dino-urging-jaw {
69
+ 0%, 100% { transform: scaleY(1); }
70
+ 50% { transform: scaleY(1.8); }
71
+ }
72
+ .mood-urging #pet-body-group {
73
+ animation: dino-urging-stomp 0.35s ease-in-out infinite;
74
+ transform-origin: 128px 220px;
75
+ }
76
+ .mood-urging #pet-mouth {
77
+ animation: dino-urging-jaw 0.35s ease-in-out infinite;
78
+ transform-origin: 128px 148px;
79
+ }
80
+
81
+ /* ── done:跺脚庆祝 ── */
82
+ @keyframes dino-done-stomp {
83
+ 0% { transform: translateY(0) scale(1); }
84
+ 30% { transform: translateY(0) scaleY(0.88) scaleX(1.1); }
85
+ 60% { transform: translateY(-10px) scale(1.08); }
86
+ 100% { transform: translateY(0) scale(1); }
87
+ }
88
+ .pet-done #pet-body-group {
89
+ animation: dino-done-stomp 0.5s ease-out 1;
90
+ transform-origin: 128px 220px;
91
+ }
@@ -39,12 +39,12 @@
39
39
  </g>
40
40
 
41
41
  <!-- Jagged mouth -->
42
- <path d="M108 148 L118 156 L128 148 L138 156 L148 148" stroke="#69f0ae" stroke-width="4" fill="none" stroke-linecap="round" filter="url(#glow)"/>
42
+ <path id="pet-mouth" d="M108 148 L118 156 L128 148 L138 156 L148 148" stroke="#69f0ae" stroke-width="4" fill="none" stroke-linecap="round" filter="url(#glow)"/>
43
43
 
44
44
  <!-- Small arms(填充块面而非线条,末端一颗圆球小手) -->
45
- <ellipse cx="31" cy="142" rx="5.5" ry="15" fill="url(#accentGrad)" transform="rotate(-34 31 142)"/>
45
+ <ellipse id="pet-arm-left" cx="31" cy="142" rx="5.5" ry="15" fill="url(#accentGrad)" transform="rotate(-34 31 142)"/>
46
46
  <circle cx="25" cy="156" r="5" fill="url(#accentGrad)"/>
47
- <ellipse cx="223" cy="142" rx="5.5" ry="15" fill="url(#accentGrad)" transform="rotate(34 223 142)"/>
47
+ <ellipse id="pet-arm-right" cx="223" cy="142" rx="5.5" ry="15" fill="url(#accentGrad)" transform="rotate(34 223 142)"/>
48
48
  <circle cx="231" cy="156" r="5" fill="url(#accentGrad)"/>
49
49
 
50
50
  <!-- Legs / feet -->
@@ -0,0 +1,44 @@
1
+ /* 史莱姆(slime-blob)专属演出:利用"形变"这个史莱姆独有的视觉语言覆盖通用规则。
2
+ * 史莱姆没有 arm-left/right/tail 等 id,通用规则里依赖这些 id 的动画(如 tool_call 摆臂、
3
+ * flustered 摆臂)对它本来就不生效,这里改用挤压/压扁形变来填补对应状态的演出。 */
4
+
5
+ /* ── mood-tired:身体压扁变矮,模拟疲惫瘫软,替代通用的"下沉" ── */
6
+ @keyframes slime-tired-squash {
7
+ 0%, 100% { transform: scaleY(1) scaleX(1); }
8
+ 50% { transform: scaleY(0.82) scaleX(1.08); }
9
+ }
10
+ .mood-tired #pet-body-group {
11
+ animation: slime-tired-squash 3.6s ease-in-out infinite;
12
+ transform-origin: 128px 200px;
13
+ }
14
+
15
+ /* ── tool_call:挤压弹跳形变代替通用双臂摆动 ── */
16
+ @keyframes slime-tool-bounce {
17
+ 0%, 100% { transform: scaleY(1) scaleX(1); }
18
+ 30% { transform: scaleY(0.85) scaleX(1.12); }
19
+ 60% { transform: scaleY(1.12) scaleX(0.9); }
20
+ }
21
+ .pet-tool #pet-body-group {
22
+ animation: slime-tool-bounce 0.5s ease-in-out infinite;
23
+ transform-origin: 128px 200px;
24
+ }
25
+
26
+ /* ── idle:呼吸感的轻微鼓起收缩,比通用的上下浮动更软糯 ── */
27
+ @keyframes slime-idle-breathe {
28
+ 0%, 100% { transform: scale(1); }
29
+ 50% { transform: scale(1.03); }
30
+ }
31
+ .pet-idle #pet-body-group {
32
+ animation: slime-idle-breathe 2.8s ease-in-out infinite;
33
+ transform-origin: 128px 138px;
34
+ }
35
+
36
+ /* ── mood-urging:急促地一颤一颤,像在催你快点 ── */
37
+ @keyframes slime-urging-jiggle {
38
+ 0%, 100% { transform: scaleY(1); }
39
+ 50% { transform: scaleY(0.92); }
40
+ }
41
+ .mood-urging #pet-body-group {
42
+ animation: slime-urging-jiggle 0.45s ease-in-out infinite;
43
+ transform-origin: 128px 200px;
44
+ }
@@ -8,7 +8,7 @@
8
8
  <feGaussianBlur stdDeviation="3" result="blur"/>
9
9
  <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
10
10
  </filter>
11
- </defs>
11
+ </defs>
12
12
  <g id="pet-body-group">
13
13
 
14
14
  <!-- Blob body -->
@@ -31,7 +31,7 @@
31
31
  </g>
32
32
 
33
33
  <!-- Smile -->
34
- <path d="M110 156 Q128 170 146 156" stroke="#0a1420" stroke-width="3.5" fill="none" stroke-linecap="round"/>
34
+ <path id="pet-mouth" d="M110 156 Q128 170 146 156" stroke="#0a1420" stroke-width="3.5" fill="none" stroke-linecap="round"/>
35
35
 
36
36
  <!-- Drips -->
37
37
  <path d="M84 216 Q84 232 92 232 Q100 232 96 216 Z" fill="url(#blobGrad)"/>
@@ -39,5 +39,5 @@
39
39
 
40
40
  <!-- Highlight -->
41
41
  <ellipse cx="92" cy="86" rx="18" ry="10" fill="#ffffff" fill-opacity="0.25"/>
42
- </g>
42
+ </g>
43
43
  </svg>
@@ -0,0 +1,73 @@
1
+ /* 字节幽灵(ghost-byte)专属演出:体现"幽灵"的飘忽与半透明质感,所有动作都是"飘"或"闪"。
2
+ * SVG 自带的 ghost body 内联 animateTransform(translateY 0/-8/0) 在我们用 CSS 接管时会被覆盖,
3
+ * 因此 .pet-idle 必须保留一个同款飘浮动画,否则该状态会失去律动;
4
+ * #pet-arm-* 不存在,tool_call 用整体半透明闪烁代替双臂摆动。 */
5
+
6
+ /* ── idle:保留原 SVG 飘浮风格的垂直浮动(替换内置动画) ── */
7
+ @keyframes ghost-idle-float {
8
+ 0%, 100% { transform: translateY(0); }
9
+ 50% { transform: translateY(-8px); }
10
+ }
11
+ .pet-idle #pet-body-group {
12
+ animation: ghost-idle-float 2.4s ease-in-out infinite;
13
+ }
14
+
15
+ /* ── thinking:垂直 + 水平小幅漂移,像在"搜魂" ── */
16
+ @keyframes ghost-think-drift {
17
+ 0%, 100% { transform: translate(0, 0); }
18
+ 25% { transform: translate(-3px, -4px); }
19
+ 50% { transform: translate(0, -8px); }
20
+ 75% { transform: translate(3px, -4px); }
21
+ }
22
+ .pet-thinking #pet-body-group {
23
+ animation: ghost-think-drift 2.8s ease-in-out infinite;
24
+ }
25
+
26
+ /* ── tool_call:身体快速半透明闪烁 + 轻微抖动(代替双臂) ── */
27
+ @keyframes ghost-tool-flicker {
28
+ 0%, 100% { transform: translateX(0); opacity: 1; }
29
+ 20% { transform: translateX(-3px); opacity: 0.5; }
30
+ 40% { transform: translateX(3px); opacity: 1; }
31
+ 60% { transform: translateX(-2px); opacity: 0.6; }
32
+ 80% { transform: translateX(2px); opacity: 1; }
33
+ }
34
+ .pet-tool #pet-body-group {
35
+ animation: ghost-tool-flicker 0.6s ease-in-out infinite;
36
+ }
37
+
38
+ /* ── mood-urging:浮得更高 + 嘴部快速张合(惊吓催促) ── */
39
+ @keyframes ghost-urging-rise {
40
+ 0%, 100% { transform: translateY(0); }
41
+ 50% { transform: translateY(-14px); }
42
+ }
43
+ @keyframes ghost-urging-mouth {
44
+ 0%, 100% { transform: scaleY(1); }
45
+ 50% { transform: scaleY(1.8); }
46
+ }
47
+ .mood-urging #pet-body-group {
48
+ animation: ghost-urging-rise 0.5s ease-in-out infinite;
49
+ }
50
+ .mood-urging #pet-mouth {
51
+ animation: ghost-urging-mouth 0.4s ease-in-out infinite;
52
+ transform-origin: 128px 142px;
53
+ }
54
+
55
+ /* ── mood-tired:沉下去 + 透明度下降,像电量耗尽的幽灵 ── */
56
+ @keyframes ghost-tired-sink {
57
+ 0%, 100% { transform: translateY(0); opacity: 1; }
58
+ 50% { transform: translateY(6px); opacity: 0.55; }
59
+ }
60
+ .mood-tired #pet-body-group {
61
+ animation: ghost-tired-sink 4.4s ease-in-out infinite;
62
+ }
63
+
64
+ /* ── done:突然显形 + 弹回 ── */
65
+ @keyframes ghost-done-pop {
66
+ 0% { transform: scale(0.85); opacity: 0.6; }
67
+ 40% { transform: scale(1.12); opacity: 1; }
68
+ 100% { transform: scale(1); opacity: 0.92; }
69
+ }
70
+ .pet-done #pet-body-group {
71
+ animation: ghost-done-pop 0.45s ease-out 1;
72
+ transform-origin: 128px 130px;
73
+ }
@@ -8,7 +8,7 @@
8
8
  <feGaussianBlur stdDeviation="3" result="blur"/>
9
9
  <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
10
10
  </filter>
11
- </defs>
11
+ </defs>
12
12
  <g id="pet-body-group">
13
13
 
14
14
  <!-- Floating shadow -->
@@ -36,6 +36,6 @@
36
36
  </g>
37
37
 
38
38
  <!-- Mouth -->
39
- <ellipse cx="128" cy="142" rx="10" ry="8" fill="#0a1420" fill-opacity="0.85"/>
40
- </g>
39
+ <ellipse id="pet-mouth" cx="128" cy="142" rx="10" ry="8" fill="#0a1420" fill-opacity="0.85"/>
40
+ </g>
41
41
  </svg>
@@ -0,0 +1,90 @@
1
+ /* 仙人掌兽(cactus-bot)专属演出:体现"仙人掌"的呆萌与刺感,动作偏迟钝、带轻微摇摆。
2
+ * #pet-arm-left/right 是两片刺臂,旋转角度小一些避免"刺"飞出去;tool_call 复用刺臂摆动。 */
3
+
4
+ /* ── thinking:整个身体轻微左右晃,像顶着烈日有点晃神 ── */
5
+ @keyframes cactus-think-sway {
6
+ 0%, 100% { transform: rotate(0deg); }
7
+ 25% { transform: rotate(-2deg); }
8
+ 75% { transform: rotate(2deg); }
9
+ }
10
+ .pet-thinking #pet-body-group {
11
+ animation: cactus-think-sway 1.4s ease-in-out infinite;
12
+ transform-origin: 128px 220px;
13
+ }
14
+
15
+ /* ── idle:非常慢的上下浮动(像在晒太阳) ── */
16
+ @keyframes cactus-idle-bob {
17
+ 0%, 100% { transform: translateY(0); }
18
+ 50% { transform: translateY(-3px); }
19
+ }
20
+ .pet-idle #pet-body-group {
21
+ animation: cactus-idle-bob 3.6s ease-in-out infinite;
22
+ }
23
+
24
+ /* ── tool_call:刺臂小幅拍打(代替通用双臂摆动) ── */
25
+ @keyframes cactus-tool-arm-left {
26
+ 0%, 100% { transform: rotate(0deg); }
27
+ 50% { transform: rotate(-15deg); }
28
+ }
29
+ @keyframes cactus-tool-arm-right {
30
+ 0%, 100% { transform: rotate(0deg); }
31
+ 50% { transform: rotate(15deg); }
32
+ }
33
+ .pet-tool #pet-arm-left {
34
+ animation: cactus-tool-arm-left 0.55s ease-in-out infinite;
35
+ transform-origin: 60px 130px;
36
+ }
37
+ .pet-tool #pet-arm-right {
38
+ animation: cactus-tool-arm-right 0.55s ease-in-out infinite 0.27s;
39
+ transform-origin: 196px 130px;
40
+ }
41
+
42
+ /* ── mood-urging:身体急促左右摇摆(像不耐烦地甩刺) ── */
43
+ @keyframes cactus-urging-wiggle {
44
+ 0%, 100% { transform: rotate(0deg); }
45
+ 25% { transform: rotate(-4deg); }
46
+ 75% { transform: rotate(4deg); }
47
+ }
48
+ .mood-urging #pet-body-group {
49
+ animation: cactus-urging-wiggle 0.35s ease-in-out infinite;
50
+ transform-origin: 128px 220px;
51
+ }
52
+
53
+ /* ── mood-tired:慢慢瘪下去 + 变暗 ── */
54
+ @keyframes cactus-tired-droop {
55
+ 0%, 100% { transform: translateY(0) scaleY(1); opacity: 1; }
56
+ 50% { transform: translateY(4px) scaleY(0.94); opacity: 0.85; }
57
+ }
58
+ .mood-tired #pet-body-group {
59
+ animation: cactus-tired-droop 4s ease-in-out infinite;
60
+ transform-origin: 128px 220px;
61
+ }
62
+
63
+ /* ── done:小弹一下 + 刺臂举起 ── */
64
+ @keyframes cactus-done-pop {
65
+ 0% { transform: scale(1); }
66
+ 40% { transform: scale(1.06); }
67
+ 100% { transform: scale(1); }
68
+ }
69
+ @keyframes cactus-done-arm-left {
70
+ 0% { transform: rotate(0deg); }
71
+ 40% { transform: rotate(-25deg); }
72
+ 100% { transform: rotate(0deg); }
73
+ }
74
+ @keyframes cactus-done-arm-right {
75
+ 0% { transform: rotate(0deg); }
76
+ 40% { transform: rotate(25deg); }
77
+ 100% { transform: rotate(0deg); }
78
+ }
79
+ .pet-done #pet-body-group {
80
+ animation: cactus-done-pop 0.4s ease-out 1;
81
+ transform-origin: 128px 220px;
82
+ }
83
+ .pet-done #pet-arm-left {
84
+ animation: cactus-done-arm-left 0.4s ease-out 1;
85
+ transform-origin: 60px 130px;
86
+ }
87
+ .pet-done #pet-arm-right {
88
+ animation: cactus-done-arm-right 0.4s ease-out 1;
89
+ transform-origin: 196px 130px;
90
+ }
@@ -26,8 +26,8 @@
26
26
  <rect x="48" y="150" width="160" height="70" rx="40" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="3"/>
27
27
 
28
28
  <!-- Spike arms(填充块面而非线条,细刺仍保留为短线装饰) -->
29
- <path d="M62 108 Q26 112 24 142 Q22 156 38 158 Q50 158 48 144 Q44 122 62 118 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
30
- <path d="M194 108 Q230 112 232 142 Q234 156 218 158 Q206 158 208 144 Q212 122 194 118 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
29
+ <path id="pet-arm-left" d="M62 108 Q26 112 24 142 Q22 156 38 158 Q50 158 48 144 Q44 122 62 118 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
30
+ <path id="pet-arm-right" d="M194 108 Q230 112 232 142 Q234 156 218 158 Q206 158 208 144 Q212 122 194 118 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
31
31
  <path d="M34 118 L24 108 M34 128 L22 124 M222 118 L232 108 M222 128 L234 124"
32
32
  stroke="url(#accentGrad)" stroke-width="3" stroke-linecap="round"/>
33
33
 
@@ -0,0 +1,63 @@
1
+ /* 水晶精灵(crystal-bot)专属演出:体现"水晶"的折射与旋转,所有动作都是几何化的旋转/缩放。
2
+ * SVG 自带 translateY 浮动动画,这里 .pet-idle 用等效浮动覆盖内置,其他状态彻底接管;
3
+ * 没有 #pet-arm-*,tool_call 改用快速旋转代替双臂摆动。 */
4
+
5
+ /* ── idle:保留并替换 SVG 内置浮动为更稳定的"原地悬停" ── */
6
+ @keyframes crystal-idle-hover {
7
+ 0%, 100% { transform: translateY(0); }
8
+ 50% { transform: translateY(-6px); }
9
+ }
10
+ .pet-idle #pet-body-group {
11
+ animation: crystal-idle-hover 3s ease-in-out infinite;
12
+ }
13
+
14
+ /* ── thinking:缓慢连续旋转(整颗水晶),模拟展示内部折射 ── */
15
+ @keyframes crystal-think-spin {
16
+ 0% { transform: rotate(0deg); }
17
+ 100% { transform: rotate(360deg); }
18
+ }
19
+ .pet-thinking #pet-body-group {
20
+ animation: crystal-think-spin 4s linear infinite;
21
+ transform-origin: 128px 128px;
22
+ }
23
+
24
+ /* ── tool_call:急促左右摇摆(代替双臂摆动),像光在晶体里来回折射 ── */
25
+ @keyframes crystal-tool-sway {
26
+ 0%, 100% { transform: rotate(-6deg); }
27
+ 50% { transform: rotate(6deg); }
28
+ }
29
+ .pet-tool #pet-body-group {
30
+ animation: crystal-tool-sway 0.4s ease-in-out infinite;
31
+ transform-origin: 128px 128px;
32
+ }
33
+
34
+ /* ── mood-urging:急促脉冲式缩放(像能量过载) ── */
35
+ @keyframes crystal-urging-pulse {
36
+ 0%, 100% { transform: scale(1); }
37
+ 50% { transform: scale(1.1); }
38
+ }
39
+ .mood-urging #pet-body-group {
40
+ animation: crystal-urging-pulse 0.3s ease-in-out infinite;
41
+ transform-origin: 128px 128px;
42
+ }
43
+
44
+ /* ── mood-tired:慢慢缩小变暗,像水晶能量耗尽 ── */
45
+ @keyframes crystal-tired-dim {
46
+ 0%, 100% { transform: scale(1); opacity: 1; }
47
+ 50% { transform: scale(0.92); opacity: 0.75; }
48
+ }
49
+ .mood-tired #pet-body-group {
50
+ animation: crystal-tired-dim 4.6s ease-in-out infinite;
51
+ transform-origin: 128px 128px;
52
+ }
53
+
54
+ /* ── done:快速自转一圈 + 回到原位 ── */
55
+ @keyframes crystal-done-twirl {
56
+ 0% { transform: rotate(0deg) scale(1); }
57
+ 50% { transform: rotate(180deg) scale(1.12); }
58
+ 100% { transform: rotate(360deg) scale(1); }
59
+ }
60
+ .pet-done #pet-body-group {
61
+ animation: crystal-done-twirl 0.55s ease-out 1;
62
+ transform-origin: 128px 128px;
63
+ }
@@ -0,0 +1,72 @@
1
+ /* 卫星兽(satellite-bot)专属演出:体现"卫星"的机械感与扫描感,动作以旋转/信号脉冲为主。
2
+ * #pet-antenna 是顶部的碟形天线(在通用 style.css 里被当成"指示灯"做透明度闪烁,这里改用旋转);
3
+ * 两侧的"翅膀"是矩形太阳能板(无 id),通过 #pet-body-group 整体扫描带动视觉。 */
4
+
5
+ /* ── idle:缓慢小幅旋转,模拟在轨道上微微漂移 ── */
6
+ @keyframes satellite-idle-drift {
7
+ 0%, 100% { transform: rotate(0deg); }
8
+ 25% { transform: rotate(-2deg); }
9
+ 75% { transform: rotate(2deg); }
10
+ }
11
+ .pet-idle #pet-body-group {
12
+ animation: satellite-idle-drift 3.4s ease-in-out infinite;
13
+ transform-origin: 128px 220px;
14
+ }
15
+
16
+ /* ── thinking:碟形天线慢速旋转(扫描天空),身体微微摆动 ── */
17
+ @keyframes satellite-think-dish {
18
+ 0% { transform: rotate(-15deg); }
19
+ 100% { transform: rotate(15deg); }
20
+ }
21
+ @keyframes satellite-think-body {
22
+ 0%, 100% { transform: rotate(0deg); }
23
+ 50% { transform: rotate(-2deg); }
24
+ }
25
+ .pet-thinking #pet-antenna {
26
+ animation: satellite-think-dish 1.6s ease-in-out infinite alternate;
27
+ transform-origin: 128px 30px;
28
+ }
29
+ .pet-thinking #pet-body-group {
30
+ animation: satellite-think-body 1.6s ease-in-out infinite;
31
+ transform-origin: 128px 220px;
32
+ }
33
+
34
+ /* ── tool_call:碟形天线快速来回扫,代替通用双臂摆动 ── */
35
+ @keyframes satellite-tool-dish {
36
+ 0%, 100% { transform: rotate(-20deg); }
37
+ 50% { transform: rotate(20deg); }
38
+ }
39
+ .pet-tool #pet-antenna {
40
+ animation: satellite-tool-dish 0.4s ease-in-out infinite;
41
+ transform-origin: 128px 30px;
42
+ }
43
+
44
+ /* ── mood-urging:信号脉冲(天线透明度快速闪烁代替通用 0.5s 旋转闪烁) ── */
45
+ @keyframes satellite-urging-pulse {
46
+ 0%, 100% { opacity: 1; }
47
+ 50% { opacity: 0.3; }
48
+ }
49
+ .mood-urging #pet-antenna {
50
+ animation: satellite-urging-pulse 0.25s ease-in-out infinite;
51
+ }
52
+
53
+ /* ── mood-bored:身体非常慢的左右扫,模拟扫描不到东西 ── */
54
+ @keyframes satellite-bored-scan {
55
+ 0%, 100% { transform: rotate(-4deg); }
56
+ 50% { transform: rotate(4deg); }
57
+ }
58
+ .mood-bored #pet-body-group {
59
+ animation: satellite-bored-scan 2.8s ease-in-out infinite;
60
+ transform-origin: 128px 220px;
61
+ }
62
+
63
+ /* ── done:快速收回(下沉 0 → -6 → 0) + 弹回 ── */
64
+ @keyframes satellite-done-deploy {
65
+ 0% { transform: translateY(0) scale(1); }
66
+ 40% { transform: translateY(-8px) scale(1.08); }
67
+ 100% { transform: translateY(0) scale(1); }
68
+ }
69
+ .pet-done #pet-body-group {
70
+ animation: satellite-done-deploy 0.5s ease-out 1;
71
+ transform-origin: 128px 220px;
72
+ }
@@ -18,7 +18,7 @@
18
18
  <!-- Antenna dish (kept 8px lower than original so the dish curve's peak stays clear
19
19
  of the viewBox top edge during the idle float animation's -6px translateY) -->
20
20
  <line x1="128" y1="24" x2="128" y2="54" stroke="url(#accentGrad)" stroke-width="4"/>
21
- <path d="M100 24 Q128 4 156 24 Q128 36 100 24 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
21
+ <path id="pet-antenna" d="M100 24 Q128 4 156 24 Q128 36 100 24 Z" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>
22
22
 
23
23
  <!-- Solar panel wings -->
24
24
  <rect x="4" y="88" width="50" height="70" rx="6" fill="url(#bodyGrad)" stroke="url(#accentGrad)" stroke-width="2.5"/>