clawd-desktop 1.0.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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/assets/LICENSE-clawd +22 -0
  4. package/assets/gif/clawd-building.gif +0 -0
  5. package/assets/gif/clawd-carrying.gif +0 -0
  6. package/assets/gif/clawd-conducting.gif +0 -0
  7. package/assets/gif/clawd-debugger.gif +0 -0
  8. package/assets/gif/clawd-error.gif +0 -0
  9. package/assets/gif/clawd-happy.gif +0 -0
  10. package/assets/gif/clawd-idle-reading.gif +0 -0
  11. package/assets/gif/clawd-idle.gif +0 -0
  12. package/assets/gif/clawd-juggling.gif +0 -0
  13. package/assets/gif/clawd-notification.gif +0 -0
  14. package/assets/gif/clawd-react-annoyed.gif +0 -0
  15. package/assets/gif/clawd-react-double-jump.gif +0 -0
  16. package/assets/gif/clawd-sleeping.gif +0 -0
  17. package/assets/gif/clawd-sweeping.gif +0 -0
  18. package/assets/gif/clawd-thinking.gif +0 -0
  19. package/assets/gif/clawd-typing.gif +0 -0
  20. package/assets/svg/clawd-about-hero.svg +202 -0
  21. package/assets/svg/clawd-collapse-sleep.svg +247 -0
  22. package/assets/svg/clawd-error.svg +94 -0
  23. package/assets/svg/clawd-happy.svg +161 -0
  24. package/assets/svg/clawd-idle-collapse.svg +101 -0
  25. package/assets/svg/clawd-idle-doze.svg +72 -0
  26. package/assets/svg/clawd-idle-follow.svg +64 -0
  27. package/assets/svg/clawd-idle-living.svg +196 -0
  28. package/assets/svg/clawd-idle-look.svg +115 -0
  29. package/assets/svg/clawd-idle-reading.svg +201 -0
  30. package/assets/svg/clawd-idle-yawn.svg +158 -0
  31. package/assets/svg/clawd-mini-alert.svg +129 -0
  32. package/assets/svg/clawd-mini-crabwalk.svg +76 -0
  33. package/assets/svg/clawd-mini-enter-sleep.svg +65 -0
  34. package/assets/svg/clawd-mini-enter.svg +115 -0
  35. package/assets/svg/clawd-mini-happy.svg +124 -0
  36. package/assets/svg/clawd-mini-idle.svg +83 -0
  37. package/assets/svg/clawd-mini-peek.svg +82 -0
  38. package/assets/svg/clawd-mini-sleep.svg +112 -0
  39. package/assets/svg/clawd-mini-typing.svg +153 -0
  40. package/assets/svg/clawd-notification.svg +149 -0
  41. package/assets/svg/clawd-react-annoyed.svg +167 -0
  42. package/assets/svg/clawd-react-double-jump.svg +229 -0
  43. package/assets/svg/clawd-react-double.svg +108 -0
  44. package/assets/svg/clawd-react-drag.svg +102 -0
  45. package/assets/svg/clawd-react-left.svg +102 -0
  46. package/assets/svg/clawd-react-right.svg +102 -0
  47. package/assets/svg/clawd-sleeping.svg +118 -0
  48. package/assets/svg/clawd-static-base.svg +21 -0
  49. package/assets/svg/clawd-wake.svg +277 -0
  50. package/assets/svg/clawd-working-building.svg +329 -0
  51. package/assets/svg/clawd-working-carrying.svg +178 -0
  52. package/assets/svg/clawd-working-conducting.svg +220 -0
  53. package/assets/svg/clawd-working-debugger.svg +245 -0
  54. package/assets/svg/clawd-working-juggling.svg +183 -0
  55. package/assets/svg/clawd-working-sweeping.svg +248 -0
  56. package/assets/svg/clawd-working-thinking.svg +196 -0
  57. package/assets/svg/clawd-working-typing.svg +273 -0
  58. package/assets/svg/clawd-working-ultrathink.svg +166 -0
  59. package/assets/svg/clawd-working-wizard.svg +98 -0
  60. package/assets/tray-icon.ico +0 -0
  61. package/bin/claude-pet.js +6 -0
  62. package/main.js +86 -0
  63. package/package.json +38 -0
  64. package/preload.js +6 -0
  65. package/renderer/avatar.js +55 -0
  66. package/renderer/index.html +14 -0
  67. package/renderer/motion.js +24 -0
  68. package/renderer/style.css +104 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KebeliSamet0
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Clawd — Desktop Pet
2
+
3
+ <p align="center">
4
+ <img src="assets/gif/clawd-typing.gif" width="120" alt="typing"/>
5
+ <img src="assets/gif/clawd-building.gif" width="120" alt="building"/>
6
+ <img src="assets/gif/clawd-juggling.gif" width="120" alt="juggling"/>
7
+ <img src="assets/gif/clawd-happy.gif" width="120" alt="happy"/>
8
+ <img src="assets/gif/clawd-sleeping.gif" width="120" alt="sleeping"/>
9
+ </p>
10
+
11
+ <p align="center"><i>A pixel-art Claude mascot that lives on your Windows desktop.</i></p>
12
+
13
+ <p align="center">
14
+ <a href="https://github.com/KebeliSamet0/clawd/releases/latest"><img src="https://img.shields.io/github/v/release/KebeliSamet0/clawd" alt="Release"/></a>
15
+ <img src="https://img.shields.io/badge/platform-Windows-blue" alt="Platform"/>
16
+ <a href="https://github.com/KebeliSamet0/clawd/stargazers"><img src="https://img.shields.io/github/stars/KebeliSamet0/clawd?style=flat&color=yellow" alt="Stars"/></a>
17
+ </p>
18
+
19
+ Transparent, frameless, always-on-top. Wanders around your screen, plays animations, lives in your system tray.
20
+
21
+ ## Download
22
+
23
+ Grab the latest installer from [Releases](../../releases/latest).
24
+
25
+ Or run via npm:
26
+
27
+ ```bash
28
+ npm install -g clawd-desktop
29
+ clawd-desktop
30
+ ```
31
+
32
+ ## Features
33
+
34
+ - Transparent & frameless window — only the character is visible
35
+ - Roams the screen randomly, reacts with different animations
36
+ - Animations: idle, walking, building, typing, thinking, sleeping, error, happy, and more
37
+ - System tray control (Show / Hide / Quit)
38
+ - Auto-starts with Windows
39
+
40
+ ## Run from Source
41
+
42
+ ```bash
43
+ npm install
44
+ npm start
45
+ ```
46
+
47
+ ## Build Installer
48
+
49
+ ```bash
50
+ npm run build
51
+ # Output: dist/ClaudePet Setup x.x.x.exe
52
+ ```
53
+
54
+ ## Stack
55
+
56
+ - Electron — window management, system tray, IPC
57
+ - Vanilla JS — animation state machine, motion engine
58
+ - CSS keyframes — sprite animations
@@ -0,0 +1,22 @@
1
+ All Rights Reserved
2
+
3
+ The artwork files in this directory and its subdirectories (including but not
4
+ limited to SVG, PNG, GIF, and ICO files) are NOT covered by the project's
5
+ source-code license. All rights are reserved by their respective copyright
6
+ holders.
7
+
8
+ Clawd character artwork:
9
+ The Clawd character is the property of Anthropic (https://www.anthropic.com).
10
+ Clawd pixel art in this project is fan-created and may not be used for
11
+ commercial purposes.
12
+
13
+ Calico cat (三花猫) artwork:
14
+ Copyright (c) 2026 鹿鹿 (rullerzhou-afk). All rights reserved.
15
+
16
+ Third-party artist contributions:
17
+ Copyright is retained by the respective artists. See individual file headers
18
+ or the project README for attribution details.
19
+
20
+ You may NOT copy, modify, distribute, or use any artwork from this directory
21
+ without explicit written permission from the copyright holder(s), except for
22
+ personal use of the Clawd on Desk application as distributed by this project.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,202 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 2 20 16" width="500" height="400">
2
+ <!-- Clawd About hero: "Deal with it" intro → freeze at 55% (cool pose, post-second-sparkle, hands not yet returning).
3
+ Adapted from themes/clawd/assets/source/clawd-experiment-put-on-v4.svg:
4
+ - 8s infinite → 4.4s forwards (plays once, freezes at terminal keyframe)
5
+ - Keyframes past 55% removed; remaining remapped from 0-55% → 0-100%
6
+ - Wrapped in <g class="breath-wrap"> for subtle breathing after intro
7
+ - Wrapped in <g id="shake-slot"> outermost — JS adds .shake class on click
8
+ -->
9
+
10
+ <defs>
11
+ <style>
12
+ .arm-right-motion {
13
+ transform-origin: 13px 10px;
14
+ animation: arm-right 4.4s ease-in-out forwards;
15
+ }
16
+ .arm-left-motion {
17
+ transform-origin: 2px 10px;
18
+ animation: arm-left 4.4s ease-in-out forwards;
19
+ }
20
+ .glasses-fly {
21
+ transform-origin: 0 0;
22
+ animation: glasses-fly 4.4s ease-in-out forwards;
23
+ }
24
+ .mood {
25
+ transform-origin: 7.5px 13px;
26
+ animation: mood 4.4s ease-in-out forwards;
27
+ }
28
+ .shadow-fade {
29
+ animation: shadow-fade 4.4s ease-in-out forwards;
30
+ }
31
+ .sparkle-near {
32
+ transform-origin: 2.5px 6.5px;
33
+ animation: sparkle-near 4.4s ease-in-out forwards;
34
+ }
35
+ .sparkle-far {
36
+ transform-origin: 3.5px 4.5px;
37
+ animation: sparkle-far 4.4s ease-in-out forwards;
38
+ }
39
+
40
+ /* Breath: kick in after intro completes; gentle infinite up-down */
41
+ .breath-wrap {
42
+ animation: breath 4s infinite ease-in-out;
43
+ animation-delay: 4.4s;
44
+ }
45
+ @keyframes breath {
46
+ 0%, 100% { transform: translateY(0); }
47
+ 50% { transform: translateY(-0.3px); }
48
+ }
49
+
50
+ /* Shake: JS toggles .shake on click; animationend removes the class */
51
+ .shake-slot {
52
+ transform-origin: 7.5px 10px;
53
+ }
54
+ .shake-slot.shake {
55
+ animation: shake 0.4s ease-in-out;
56
+ }
57
+ @keyframes shake {
58
+ 0%, 100% { transform: rotate(0); }
59
+ 20% { transform: rotate(-3deg); }
60
+ 60% { transform: rotate(3deg); }
61
+ 80% { transform: rotate(-2deg); }
62
+ }
63
+
64
+ /* Right arm: idle → raise → hold → cool pose (freeze at translate(0.5,1)) */
65
+ @keyframes arm-right {
66
+ 0%, 9% { transform: none; }
67
+ 15%, 33% { transform: translateY(-3px) rotate(-90deg); }
68
+ 45%, 73% { transform: translate(-1px, -1px); }
69
+ 82%, 100% { transform: translate(0.5px, 1px); }
70
+ }
71
+
72
+ /* Left arm: idle → hold → cool pose (freeze at translate(-0.5,1)) */
73
+ @keyframes arm-left {
74
+ 0%, 27% { transform: none; }
75
+ 45%, 73% { transform: translate(1px, -1px); }
76
+ 82%, 100% { transform: translate(-0.5px, 1px); }
77
+ }
78
+
79
+ /* Glasses: invisible → summon → fly to face → display (freeze at translate(1.325,7.375) scale(0.65)) */
80
+ @keyframes glasses-fly {
81
+ 0%, 15% { transform: translate(10.15px, 3.25px) scale(0.3); opacity: 0; }
82
+ 22%, 33% { transform: translate(10.15px, 3.25px) scale(0.3); opacity: 1; }
83
+ 55%, 100% { transform: translate(1.325px, 7.375px) scale(0.65); opacity: 1; }
84
+ }
85
+
86
+ /* Mood: single head shake mid-intro → cool pose tilt (freeze at +1deg) */
87
+ @keyframes mood {
88
+ 0%, 55% { transform: rotate(0deg); }
89
+ 60% { transform: rotate(1deg); }
90
+ 65% { transform: rotate(-1deg); }
91
+ 73% { transform: rotate(0deg); }
92
+ 82%, 100% { transform: rotate(1deg); }
93
+ }
94
+
95
+ /* Hand shadows: visible only during hold periods */
96
+ @keyframes shadow-fade {
97
+ 0%, 40% { opacity: 0; }
98
+ 51%, 76% { opacity: 1; }
99
+ 87%, 100% { opacity: 0; }
100
+ }
101
+
102
+ /* Sparkle near (small, glasses corner): flashes mid-pose then fades */
103
+ @keyframes sparkle-near {
104
+ 0%, 73% { opacity: 0; transform: scale(0.4); }
105
+ 75% { opacity: 1; transform: scale(0.7); }
106
+ 78% { opacity: 0.7; transform: scale(0.5); }
107
+ 80%, 100% { opacity: 0; transform: scale(0.4); }
108
+ }
109
+
110
+ /* Sparkle far (big, upper-left void): peaks late, faded before freeze */
111
+ @keyframes sparkle-far {
112
+ 0%, 84% { opacity: 0; transform: scale(0.5); }
113
+ 87% { opacity: 1; transform: scale(1.4); }
114
+ 91% { opacity: 0.9; transform: scale(1.2); }
115
+ 96%, 100% { opacity: 0; transform: scale(0.6); }
116
+ }
117
+ </style>
118
+
119
+ <clipPath id="inside-torso">
120
+ <rect x="2" y="6" width="11" height="7"/>
121
+ </clipPath>
122
+ </defs>
123
+
124
+ <g class="shake-slot" id="shake-slot">
125
+ <rect id="ground-shadow" x="3" y="15" width="9" height="1" fill="#000000" opacity="0.5"/>
126
+
127
+ <g class="breath-wrap">
128
+ <g class="mood">
129
+ <g id="master-group">
130
+
131
+ <g id="legs" fill="#DE886D">
132
+ <rect x="3" y="13" width="1" height="2"/>
133
+ <rect x="5" y="13" width="1" height="2"/>
134
+ <rect x="9" y="13" width="1" height="2"/>
135
+ <rect x="11" y="13" width="1" height="2"/>
136
+ </g>
137
+
138
+ <rect x="2" y="6" width="11" height="7" fill="#DE886D"/>
139
+
140
+ <g clip-path="url(#inside-torso)" class="shadow-fade">
141
+ <g class="arm-left-motion">
142
+ <rect x="0" y="9" width="2.4" height="2.4" fill="#A85A3A"/>
143
+ </g>
144
+ <g class="arm-right-motion">
145
+ <rect x="12.6" y="9" width="2.4" height="2.4" fill="#A85A3A"/>
146
+ </g>
147
+ </g>
148
+
149
+ <g fill="#000000">
150
+ <rect x="4" y="8" width="1" height="2"/>
151
+ <rect x="10" y="8" width="1" height="2"/>
152
+ </g>
153
+
154
+ <g class="glasses-fly">
155
+ <g fill="#000000">
156
+ <rect x="0" y="0" width="19" height="1"/>
157
+ <rect x="0" y="1" width="8" height="1"/>
158
+ <rect x="11" y="1" width="8" height="1"/>
159
+ <rect x="0" y="2" width="8" height="1"/>
160
+ <rect x="11" y="2" width="8" height="1"/>
161
+ <rect x="1" y="3" width="6" height="1"/>
162
+ <rect x="12" y="3" width="6" height="1"/>
163
+ <rect x="2" y="4" width="4" height="1"/>
164
+ <rect x="13" y="4" width="4" height="1"/>
165
+ </g>
166
+ <g fill="#FFFFFF">
167
+ <rect x="5" y="1" width="1" height="1"/>
168
+ <rect x="4" y="2" width="1" height="1"/>
169
+ <rect x="16" y="1" width="1" height="1"/>
170
+ <rect x="15" y="2" width="1" height="1"/>
171
+ </g>
172
+ </g>
173
+
174
+ <g class="arm-left-motion">
175
+ <rect x="0" y="9" width="2" height="2" fill="#DE886D"/>
176
+ </g>
177
+
178
+ <g class="arm-right-motion">
179
+ <rect x="13" y="9" width="2" height="2" fill="#DE886D"/>
180
+ </g>
181
+
182
+ <g class="sparkle-near" fill="#FFFFFF">
183
+ <rect x="2" y="6" width="1" height="1"/>
184
+ <rect x="2" y="5" width="1" height="1"/>
185
+ <rect x="2" y="7" width="1" height="1"/>
186
+ <rect x="1" y="6" width="1" height="1"/>
187
+ <rect x="3" y="6" width="1" height="1"/>
188
+ </g>
189
+
190
+ <g class="sparkle-far" fill="#FFFFFF">
191
+ <rect x="3" y="4" width="1" height="1"/>
192
+ <rect x="3" y="3" width="1" height="1"/>
193
+ <rect x="3" y="5" width="1" height="1"/>
194
+ <rect x="2" y="4" width="1" height="1"/>
195
+ <rect x="4" y="4" width="1" height="1"/>
196
+ </g>
197
+
198
+ </g>
199
+ </g>
200
+ </g>
201
+ </g>
202
+ </svg>
@@ -0,0 +1,247 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="-15 -25 45 45" width="500" height="500" shape-rendering="crispEdges">
2
+ <defs>
3
+ <style>
4
+ /* Collapse (0-1s) → Sleep breathing + Zzz (1s onwards, infinite) */
5
+ /* Start pose matches yawn end: body scale(1.05,0.95) translate(0,1px), eyes shut, arms down */
6
+
7
+ .rest-shadow-breathe {
8
+ transform-origin: 7.5px 15.5px;
9
+ animation: sleep-shadow 4.5s infinite ease-in-out 1s;
10
+ }
11
+
12
+ .rest-shadow-form {
13
+ transform-origin: 7.5px 15.5px;
14
+ animation: rest-shadow-form 1s linear forwards;
15
+ }
16
+
17
+ .rest-breathe {
18
+ transform-origin: 7.5px 15px;
19
+ animation: sleep-breathe 4.5s infinite ease-in-out 1s;
20
+ }
21
+
22
+ .rest-body-frame {
23
+ transform-origin: 7.5px 13px;
24
+ animation: rest-body-frame 1s linear forwards;
25
+ }
26
+
27
+ .rest-torso {
28
+ transform-origin: 2px 6px;
29
+ animation: rest-torso 1s linear forwards;
30
+ }
31
+
32
+ .rest-arm-l {
33
+ transform-origin: 1px 10px;
34
+ animation: rest-arm-l 1s linear forwards;
35
+ }
36
+
37
+ .rest-arm-r {
38
+ transform-origin: 14px 10px;
39
+ animation: rest-arm-r 1s linear forwards;
40
+ }
41
+
42
+ .rest-eye-l {
43
+ transform-origin: 4px 8px;
44
+ animation: rest-eye-l 1s linear forwards;
45
+ }
46
+
47
+ .rest-eye-r {
48
+ transform-origin: 10px 8px;
49
+ animation: rest-eye-r 1s linear forwards;
50
+ }
51
+
52
+ .rest-leg {
53
+ animation: rest-leg 1s linear forwards;
54
+ }
55
+
56
+ .rest-leg.left-outer { transform-origin: 3px 12px; }
57
+ .rest-leg.left-inner { transform-origin: 5px 12px; }
58
+ .rest-leg.right-inner { transform-origin: 9px 12px; }
59
+ .rest-leg.right-outer { transform-origin: 11px 12px; }
60
+
61
+ .z-particle { opacity: 0; }
62
+ .z1 { animation: float-1 6s infinite ease-in-out 1s; }
63
+ .z2 { animation: float-2 6s infinite ease-in-out 3s; }
64
+ .z3 { animation: float-3 6s infinite ease-in-out 5s; }
65
+
66
+ /* Shadow: narrow (matching yawn end) → wide (sleeping) */
67
+ @keyframes rest-shadow-form {
68
+ 0% { transform: scaleX(0.556); opacity: 0.55; }
69
+ 4% { transform: scaleX(0.574); opacity: 0.548; }
70
+ 14% { transform: scaleX(0.61); opacity: 0.54; }
71
+ 28% { transform: scaleX(0.665); opacity: 0.522; }
72
+ 42% { transform: scaleX(0.74); opacity: 0.5; }
73
+ 68% { transform: scaleX(0.9); opacity: 0.45; }
74
+ 86% { transform: scaleX(1.02); opacity: 0.41; }
75
+ 100% { transform: scaleX(1); opacity: 0.4; }
76
+ }
77
+
78
+ /* Body frame: yawn-end squash → neutral (sleeping base) */
79
+ @keyframes rest-body-frame {
80
+ 0% { transform: scale(1.05, 0.95) translate(0, 1px); }
81
+ 4% { transform: scale(1.058, 0.94) translate(0, 1.1px); }
82
+ 14% { transform: scale(1.072, 0.915) translate(0, 1.32px); }
83
+ 28% { transform: scale(1.09, 0.875) translate(0, 1.68px); }
84
+ 40% { transform: scale(1.1, 0.84) translate(0, 1.95px); }
85
+ 66% { transform: scale(1.05, 0.9) translate(0, 1.05px); }
86
+ 84% { transform: scale(1.01, 0.98) translate(0, 0.22px); }
87
+ 100% { transform: scale(1, 1) translate(0, 0); }
88
+ }
89
+
90
+ /* Torso: standing → splooted flat */
91
+ @keyframes rest-torso {
92
+ 0% { transform: translate(0, 0) scale(1, 1); }
93
+ 4% { transform: translate(-0.02px, 0.08px) scale(1.004, 0.998); }
94
+ 14% { transform: translate(-0.1px, 0.34px) scale(1.018, 0.985); }
95
+ 28% { transform: translate(-0.26px, 1.02px) scale(1.045, 0.94); }
96
+ 44% { transform: translate(-0.4px, 1.75px) scale(1.08, 0.9); }
97
+ 68% { transform: translate(-0.8px, 3.1px) scale(1.14, 0.8); }
98
+ 86% { transform: translate(-1.05px, 3.95px) scale(1.19, 0.72); }
99
+ 100% { transform: translate(-1px, 4px) scale(1.1818, 0.7143); }
100
+ }
101
+
102
+ /* Arms: relaxed down → flat on ground */
103
+ @keyframes rest-arm-l {
104
+ 0% { transform: translate(0, 1px) rotate(-15deg); }
105
+ 4% { transform: translate(-0.03px, 1.08px) rotate(-14.5deg); }
106
+ 14% { transform: translate(-0.11px, 1.34px) rotate(-13deg); }
107
+ 28% { transform: translate(-0.27px, 1.98px) rotate(-9deg); }
108
+ 44% { transform: translate(-0.45px, 2.45px) rotate(-7deg); }
109
+ 68% { transform: translate(-0.8px, 3.35px) rotate(-2deg); }
110
+ 86% { transform: translate(-1.05px, 4.05px) rotate(0deg); }
111
+ 100% { transform: translate(-1px, 4px) rotate(0deg); }
112
+ }
113
+
114
+ @keyframes rest-arm-r {
115
+ 0% { transform: translate(0, 1px) rotate(15deg); }
116
+ 4% { transform: translate(0.03px, 1.08px) rotate(14.5deg); }
117
+ 14% { transform: translate(0.11px, 1.34px) rotate(13deg); }
118
+ 28% { transform: translate(0.27px, 1.98px) rotate(9deg); }
119
+ 44% { transform: translate(0.45px, 2.45px) rotate(7deg); }
120
+ 68% { transform: translate(0.8px, 3.35px) rotate(2deg); }
121
+ 86% { transform: translate(1.05px, 4.05px) rotate(0deg); }
122
+ 100% { transform: translate(1px, 4px) rotate(0deg); }
123
+ }
124
+
125
+ /* Eyes: shut (scaleY 0.1) → sleeping dashes */
126
+ @keyframes rest-eye-l {
127
+ 0% { transform: scale(1, 0.1); }
128
+ 4% { transform: translate(0, 0.06px) scale(1.015, 0.1); }
129
+ 14% { transform: translate(0, 0.28px) scale(1.06, 0.1); }
130
+ 24% { transform: translate(0, 0.6px) scale(1.12, 0.1); }
131
+ 52% { transform: translate(-0.15px, 2.1px) scale(1.45, 0.12); }
132
+ 78% { transform: translate(-0.35px, 3.8px) scale(1.82, 0.17); }
133
+ 100% { transform: translate(-0.5px, 4.5px) scale(2, 0.2); }
134
+ }
135
+
136
+ @keyframes rest-eye-r {
137
+ 0% { transform: scale(1, 0.1); }
138
+ 4% { transform: translate(0, 0.06px) scale(1.015, 0.1); }
139
+ 14% { transform: translate(0, 0.28px) scale(1.06, 0.1); }
140
+ 24% { transform: translate(0, 0.6px) scale(1.12, 0.1); }
141
+ 52% { transform: translate(-0.15px, 2.1px) scale(1.45, 0.12); }
142
+ 78% { transform: translate(-0.35px, 3.8px) scale(1.82, 0.17); }
143
+ 100% { transform: translate(-0.5px, 4.5px) scale(2, 0.2); }
144
+ }
145
+
146
+ /* Legs: standing → short stubs */
147
+ @keyframes rest-leg {
148
+ 0% { transform: translate(0, 0) scale(1, 1); }
149
+ 4% { transform: translate(0, -0.03px) scale(1, 0.985); }
150
+ 14% { transform: translate(0, -0.14px) scale(1, 0.93); }
151
+ 44% { transform: translate(0, -0.4px) scale(1, 0.82); }
152
+ 68% { transform: translate(0, -1.4px) scale(1, 0.6); }
153
+ 84% { transform: translate(0, -2.4px) scale(1, 0.42); }
154
+ 100% { transform: translate(0, -3px) scale(1, 0.3333); }
155
+ }
156
+
157
+ /* Sleep breathing loop */
158
+ @keyframes sleep-breathe {
159
+ 0%, 80%, 100% { transform: scale(1, 1); }
160
+ 30%, 40% { transform: scale(1.02, 1.25); }
161
+ }
162
+
163
+ @keyframes sleep-shadow {
164
+ 0%, 80%, 100% { transform: scaleX(1); opacity: 0.4; }
165
+ 30%, 40% { transform: scaleX(1.05); opacity: 0.5; }
166
+ }
167
+
168
+ /* Zzz particle floats */
169
+ @keyframes float-1 {
170
+ 0% { transform: translate(5px, 8px) scale(0.4); opacity: 0; }
171
+ 10% { opacity: 1; }
172
+ 30% { transform: translate(9px, 4px) scale(0.6); }
173
+ 50% { transform: translate(4px, 0px) scale(0.8); }
174
+ 70% { transform: translate(8px, -4px) scale(1); }
175
+ 90% { opacity: 0.8; }
176
+ 100% { transform: translate(6px, -8px) scale(1.1); opacity: 0; }
177
+ }
178
+
179
+ @keyframes float-2 {
180
+ 0% { transform: translate(8px, 9px) scale(0.3); opacity: 0; }
181
+ 10% { opacity: 1; }
182
+ 30% { transform: translate(5px, 5px) scale(0.5); }
183
+ 50% { transform: translate(9px, 1px) scale(0.7); }
184
+ 70% { transform: translate(6px, -3px) scale(0.9); }
185
+ 90% { opacity: 0.8; }
186
+ 100% { transform: translate(8px, -7px) scale(1); opacity: 0; }
187
+ }
188
+
189
+ @keyframes float-3 {
190
+ 0% { transform: translate(6px, 7px) scale(0.5); opacity: 0; }
191
+ 10% { opacity: 1; }
192
+ 30% { transform: translate(9px, 3px) scale(0.7); }
193
+ 50% { transform: translate(4px, -1px) scale(0.9); }
194
+ 70% { transform: translate(8px, -5px) scale(1.1); }
195
+ 90% { opacity: 0.8; }
196
+ 100% { transform: translate(5px, -9px) scale(1.2); opacity: 0; }
197
+ }
198
+ </style>
199
+
200
+ <g id="pixel-z">
201
+ <rect x="0" y="0" width="4" height="1"/>
202
+ <rect x="2" y="1" width="1" height="1"/>
203
+ <rect x="1" y="2" width="1" height="1"/>
204
+ <rect x="0" y="3" width="4" height="1"/>
205
+ </g>
206
+
207
+ <g id="pixel-z-small">
208
+ <rect x="0" y="0" width="3" height="1"/>
209
+ <rect x="1" y="1" width="1" height="1"/>
210
+ <rect x="0" y="2" width="3" height="1"/>
211
+ </g>
212
+ </defs>
213
+
214
+ <!-- Shadow -->
215
+ <g class="rest-shadow-breathe">
216
+ <rect class="rest-shadow-form" x="-1" y="15" width="17" height="1" fill="#000000" opacity="0.4"/>
217
+ </g>
218
+
219
+ <!-- Zzz particles -->
220
+ <use href="#pixel-z" class="z-particle z1" fill="#90A4AE"/>
221
+ <use href="#pixel-z-small" class="z-particle z2" fill="#B0BEC5"/>
222
+ <use href="#pixel-z" class="z-particle z3" fill="#CFD8DC"/>
223
+
224
+ <!-- Body -->
225
+ <g class="rest-breathe">
226
+ <g fill="#DE886D">
227
+ <rect class="rest-leg left-outer" x="3" y="12" width="1" height="3"/>
228
+ <rect class="rest-leg left-inner" x="5" y="12" width="1" height="3"/>
229
+ <rect class="rest-leg right-inner" x="9" y="12" width="1" height="3"/>
230
+ <rect class="rest-leg right-outer" x="11" y="12" width="1" height="3"/>
231
+ </g>
232
+
233
+ <g class="rest-body-frame">
234
+ <rect class="rest-torso" x="2" y="6" width="11" height="7" fill="#DE886D"/>
235
+ <g class="rest-arm-l">
236
+ <rect x="0" y="9" width="2" height="2" fill="#DE886D"/>
237
+ </g>
238
+ <g class="rest-arm-r">
239
+ <rect x="13" y="9" width="2" height="2" fill="#DE886D"/>
240
+ </g>
241
+ <g fill="#000000">
242
+ <rect class="rest-eye-l" x="4" y="8" width="1" height="2"/>
243
+ <rect class="rest-eye-r" x="10" y="8" width="1" height="2"/>
244
+ </g>
245
+ </g>
246
+ </g>
247
+ </svg>