@mumulinya167/ccm-pet-assets 2.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 (178) hide show
  1. package/README.md +4 -0
  2. package/assets/calico/calico-collapsing.apng +0 -0
  3. package/assets/calico/calico-dozing.apng +0 -0
  4. package/assets/calico/calico-error.apng +0 -0
  5. package/assets/calico/calico-happy.apng +0 -0
  6. package/assets/calico/calico-idle-follow.svg +324 -0
  7. package/assets/calico/calico-idle.apng +0 -0
  8. package/assets/calico/calico-mini-alert.apng +0 -0
  9. package/assets/calico/calico-mini-crabwalk.apng +0 -0
  10. package/assets/calico/calico-mini-enter.apng +0 -0
  11. package/assets/calico/calico-mini-happy.apng +0 -0
  12. package/assets/calico/calico-mini-idle.apng +0 -0
  13. package/assets/calico/calico-mini-peek.apng +0 -0
  14. package/assets/calico/calico-mini-sleep.apng +0 -0
  15. package/assets/calico/calico-notification.apng +0 -0
  16. package/assets/calico/calico-react-drag.apng +0 -0
  17. package/assets/calico/calico-react-left.apng +0 -0
  18. package/assets/calico/calico-react-poke.apng +0 -0
  19. package/assets/calico/calico-sleeping.apng +0 -0
  20. package/assets/calico/calico-thinking.apng +0 -0
  21. package/assets/calico/calico-waking.apng +0 -0
  22. package/assets/calico/calico-working-building.apng +0 -0
  23. package/assets/calico/calico-working-carrying.apng +0 -0
  24. package/assets/calico/calico-working-conducting.apng +0 -0
  25. package/assets/calico/calico-working-juggling.apng +0 -0
  26. package/assets/calico/calico-working-sweeping.apng +0 -0
  27. package/assets/calico/calico-working-typing.apng +0 -0
  28. package/assets/calico/calico-yawning.apng +0 -0
  29. package/assets/calico.svg +324 -0
  30. package/assets/clawd/LICENSE +22 -0
  31. package/assets/clawd/clawd-about-hero.svg +202 -0
  32. package/assets/clawd/clawd-collapse-sleep.svg +247 -0
  33. package/assets/clawd/clawd-error.svg +94 -0
  34. package/assets/clawd/clawd-happy.svg +161 -0
  35. package/assets/clawd/clawd-headphones-groove.svg +194 -0
  36. package/assets/clawd/clawd-idle-bubble.svg +180 -0
  37. package/assets/clawd/clawd-idle-collapse.svg +101 -0
  38. package/assets/clawd/clawd-idle-doze.svg +72 -0
  39. package/assets/clawd/clawd-idle-follow.svg +64 -0
  40. package/assets/clawd/clawd-idle-living.svg +196 -0
  41. package/assets/clawd/clawd-idle-look.svg +115 -0
  42. package/assets/clawd/clawd-idle-reading.svg +252 -0
  43. package/assets/clawd/clawd-idle-yawn.svg +158 -0
  44. package/assets/clawd/clawd-mini-alert.svg +129 -0
  45. package/assets/clawd/clawd-mini-crabwalk.svg +76 -0
  46. package/assets/clawd/clawd-mini-enter-sleep.svg +64 -0
  47. package/assets/clawd/clawd-mini-enter.svg +114 -0
  48. package/assets/clawd/clawd-mini-happy.svg +124 -0
  49. package/assets/clawd/clawd-mini-idle.svg +83 -0
  50. package/assets/clawd/clawd-mini-peek.svg +82 -0
  51. package/assets/clawd/clawd-mini-sleep.svg +112 -0
  52. package/assets/clawd/clawd-mini-typing.svg +153 -0
  53. package/assets/clawd/clawd-notification.svg +438 -0
  54. package/assets/clawd/clawd-react-annoyed.svg +167 -0
  55. package/assets/clawd/clawd-react-double-jump.svg +229 -0
  56. package/assets/clawd/clawd-react-double.svg +108 -0
  57. package/assets/clawd/clawd-react-drag.svg +102 -0
  58. package/assets/clawd/clawd-react-left.svg +102 -0
  59. package/assets/clawd/clawd-react-right.svg +102 -0
  60. package/assets/clawd/clawd-sleeping.svg +118 -0
  61. package/assets/clawd/clawd-static-base.svg +21 -0
  62. package/assets/clawd/clawd-wake.svg +277 -0
  63. package/assets/clawd/clawd-working-building.svg +329 -0
  64. package/assets/clawd/clawd-working-carrying.svg +178 -0
  65. package/assets/clawd/clawd-working-debugger.svg +245 -0
  66. package/assets/clawd/clawd-working-juggling.svg +183 -0
  67. package/assets/clawd/clawd-working-sweeping.svg +248 -0
  68. package/assets/clawd/clawd-working-thinking.svg +501 -0
  69. package/assets/clawd/clawd-working-typing-boss.svg +307 -0
  70. package/assets/clawd/clawd-working-typing.svg +273 -0
  71. package/assets/clawd/clawd-working-ultrathink.svg +166 -0
  72. package/assets/clawd/clawd-working-wizard.svg +356 -0
  73. package/assets/clawd.svg +64 -0
  74. package/assets/cloudling/cloudling/cloudling-attention.svg +380 -0
  75. package/assets/cloudling/cloudling/cloudling-building.svg +667 -0
  76. package/assets/cloudling/cloudling/cloudling-carrying.svg +604 -0
  77. package/assets/cloudling/cloudling/cloudling-conducting.svg +616 -0
  78. package/assets/cloudling/cloudling/cloudling-dozing-to-sleeping.svg +578 -0
  79. package/assets/cloudling/cloudling/cloudling-dozing.svg +358 -0
  80. package/assets/cloudling/cloudling/cloudling-error.svg +428 -0
  81. package/assets/cloudling/cloudling/cloudling-idle-reading.svg +658 -0
  82. package/assets/cloudling/cloudling/cloudling-idle-to-dozing.svg +568 -0
  83. package/assets/cloudling/cloudling/cloudling-idle-to-sleeping.svg +811 -0
  84. package/assets/cloudling/cloudling/cloudling-idle.svg +255 -0
  85. package/assets/cloudling/cloudling/cloudling-juggling.svg +648 -0
  86. package/assets/cloudling/cloudling/cloudling-mini-alert.svg +390 -0
  87. package/assets/cloudling/cloudling/cloudling-mini-crabwalk.svg +335 -0
  88. package/assets/cloudling/cloudling/cloudling-mini-enter-roll-in.svg +226 -0
  89. package/assets/cloudling/cloudling/cloudling-mini-enter-sleep.svg +232 -0
  90. package/assets/cloudling/cloudling/cloudling-mini-happy.svg +371 -0
  91. package/assets/cloudling/cloudling/cloudling-mini-idle.svg +279 -0
  92. package/assets/cloudling/cloudling/cloudling-mini-peek.svg +328 -0
  93. package/assets/cloudling/cloudling/cloudling-mini-sleep.svg +260 -0
  94. package/assets/cloudling/cloudling/cloudling-mini-typing.svg +692 -0
  95. package/assets/cloudling/cloudling/cloudling-notification.svg +494 -0
  96. package/assets/cloudling/cloudling/cloudling-react-drag.svg +83 -0
  97. package/assets/cloudling/cloudling/cloudling-sleeping-to-idle.svg +555 -0
  98. package/assets/cloudling/cloudling/cloudling-sleeping.svg +500 -0
  99. package/assets/cloudling/cloudling/cloudling-sweeping.svg +292 -0
  100. package/assets/cloudling/cloudling/cloudling-thinking.svg +720 -0
  101. package/assets/cloudling/cloudling/cloudling-typing.svg +354 -0
  102. package/assets/cloudling/cloudling-attention.svg +380 -0
  103. package/assets/cloudling/cloudling-building.svg +667 -0
  104. package/assets/cloudling/cloudling-carrying.svg +604 -0
  105. package/assets/cloudling/cloudling-conducting.svg +616 -0
  106. package/assets/cloudling/cloudling-dozing-to-sleeping.svg +578 -0
  107. package/assets/cloudling/cloudling-dozing.svg +358 -0
  108. package/assets/cloudling/cloudling-error.svg +428 -0
  109. package/assets/cloudling/cloudling-idle-reading.svg +658 -0
  110. package/assets/cloudling/cloudling-idle-to-dozing.svg +568 -0
  111. package/assets/cloudling/cloudling-idle-to-sleeping.svg +811 -0
  112. package/assets/cloudling/cloudling-idle.svg +255 -0
  113. package/assets/cloudling/cloudling-juggling.svg +648 -0
  114. package/assets/cloudling/cloudling-mini-alert.svg +390 -0
  115. package/assets/cloudling/cloudling-mini-crabwalk.svg +335 -0
  116. package/assets/cloudling/cloudling-mini-enter-roll-in.svg +226 -0
  117. package/assets/cloudling/cloudling-mini-enter-sleep.svg +232 -0
  118. package/assets/cloudling/cloudling-mini-happy.svg +371 -0
  119. package/assets/cloudling/cloudling-mini-idle.svg +279 -0
  120. package/assets/cloudling/cloudling-mini-peek.svg +328 -0
  121. package/assets/cloudling/cloudling-mini-sleep.svg +260 -0
  122. package/assets/cloudling/cloudling-mini-typing.svg +692 -0
  123. package/assets/cloudling/cloudling-notification.svg +494 -0
  124. package/assets/cloudling/cloudling-react-drag.svg +83 -0
  125. package/assets/cloudling/cloudling-sleeping-to-idle.svg +555 -0
  126. package/assets/cloudling/cloudling-sleeping.svg +500 -0
  127. package/assets/cloudling/cloudling-sweeping.svg +292 -0
  128. package/assets/cloudling/cloudling-thinking.svg +720 -0
  129. package/assets/cloudling/cloudling-typing.svg +354 -0
  130. package/assets/cloudling.svg +255 -0
  131. package/assets/ghost-attention.svg +19 -0
  132. package/assets/ghost-carrying.svg +19 -0
  133. package/assets/ghost-collapsing.svg +19 -0
  134. package/assets/ghost-dozing.svg +23 -0
  135. package/assets/ghost-error.svg +19 -0
  136. package/assets/ghost-happy.svg +23 -0
  137. package/assets/ghost-idle-action1.svg +19 -0
  138. package/assets/ghost-idle-action2.svg +19 -0
  139. package/assets/ghost-idle-action3.svg +19 -0
  140. package/assets/ghost-idle.svg +11 -0
  141. package/assets/ghost-juggling.svg +19 -0
  142. package/assets/ghost-notification.svg +19 -0
  143. package/assets/ghost-react-double.svg +23 -0
  144. package/assets/ghost-react-drag.svg +23 -0
  145. package/assets/ghost-react-left.svg +19 -0
  146. package/assets/ghost-react-right.svg +19 -0
  147. package/assets/ghost-sleeping.svg +19 -0
  148. package/assets/ghost-sweeping.svg +19 -0
  149. package/assets/ghost-thinking.svg +19 -0
  150. package/assets/ghost-waking.svg +19 -0
  151. package/assets/ghost-working.svg +19 -0
  152. package/assets/ghost-yawning.svg +23 -0
  153. package/assets/ghost.svg +11 -0
  154. package/assets/robot-attention.svg +19 -0
  155. package/assets/robot-carrying.svg +19 -0
  156. package/assets/robot-collapsing.svg +19 -0
  157. package/assets/robot-dozing.svg +23 -0
  158. package/assets/robot-error.svg +19 -0
  159. package/assets/robot-happy.svg +23 -0
  160. package/assets/robot-idle-action1.svg +19 -0
  161. package/assets/robot-idle-action2.svg +19 -0
  162. package/assets/robot-idle-action3.svg +19 -0
  163. package/assets/robot-idle.svg +11 -0
  164. package/assets/robot-juggling.svg +19 -0
  165. package/assets/robot-notification.svg +19 -0
  166. package/assets/robot-react-double.svg +23 -0
  167. package/assets/robot-react-drag.svg +23 -0
  168. package/assets/robot-react-left.svg +19 -0
  169. package/assets/robot-react-right.svg +19 -0
  170. package/assets/robot-sleeping.svg +19 -0
  171. package/assets/robot-sweeping.svg +19 -0
  172. package/assets/robot-thinking.svg +19 -0
  173. package/assets/robot-waking.svg +19 -0
  174. package/assets/robot-working.svg +19 -0
  175. package/assets/robot-yawning.svg +23 -0
  176. package/assets/robot.svg +11 -0
  177. package/manifest.json +889 -0
  178. package/package.json +18 -0
@@ -0,0 +1,279 @@
1
+ <svg id="cloudling" xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6 36 36" preserveAspectRatio="xMidYMid meet">
2
+ <style><![CDATA[
3
+ .v {
4
+ text-align: right;
5
+ font: 600 10px ui-monospace, SFMono-Regular, Menlo, monospace;
6
+ color: #7A9DFF;
7
+ }
8
+ .edge-rim-tight { stroke-opacity: .9; }
9
+ .edge-rim-soft { stroke-opacity: .75; }
10
+ .edge-contact { stroke-opacity: .9; }
11
+ @media (prefers-color-scheme: light) {
12
+ .v { color: #3941FF; }
13
+ .edge-rim-tight { stroke-opacity: .95; }
14
+ .edge-rim-soft { stroke-opacity: .85; }
15
+ .edge-contact { stroke-opacity: .95; }
16
+ .cloud-drop-shadow { flood-opacity: .13; }
17
+ .food-cloud-shadow { flood-opacity: .28; flood-color: #5060FF; }
18
+ .food-cloud > path {
19
+ stroke: #5870E8 !important;
20
+ stroke-width: 1.2 !important;
21
+ stroke-opacity: .9 !important;
22
+ vector-effect: non-scaling-stroke !important;
23
+ }
24
+ }
25
+ ]]></style>
26
+ <defs>
27
+ <linearGradient id="body-grad" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
28
+ <stop offset="0" stop-color="#93c5fd"/>
29
+ <stop offset="0.5" stop-color="#60a5fa"/>
30
+ <stop offset="1" stop-color="#3b82f6"/>
31
+ </linearGradient>
32
+ <linearGradient id="eye-grad" x1="12" y1="3" x2="12" y2="21" gradientUnits="userSpaceOnUse">
33
+ <stop offset="0" stop-color="#B1A7FF"/>
34
+ <stop offset="0.5" stop-color="#7A9DFF"/>
35
+ <stop offset="1" stop-color="#3941FF"/>
36
+ </linearGradient>
37
+ <radialGradient id="hi-grad" cx="0.45" cy="0.25" r="0.55">
38
+ <stop offset="0" stop-color="#93c5fd" stop-opacity="0.9"/>
39
+ <stop offset="1" stop-color="#93c5fd" stop-opacity="0"/>
40
+ </radialGradient>
41
+ <filter id="drop" x="-40%" y="-40%" width="180%" height="180%">
42
+ <feDropShadow class="cloud-drop-shadow" dx="0" dy="0.55" stdDeviation="0.72" flood-color="#3941FF" flood-opacity="0.17"/>
43
+ </filter>
44
+ <filter id="edge-blur" x="-40%" y="-40%" width="180%" height="180%">
45
+ <feGaussianBlur stdDeviation="0.16"/>
46
+ </filter>
47
+ <path id="cloud-shape" d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388z"/>
48
+ <clipPath id="cloud-clip">
49
+ <use href="#cloud-shape"/>
50
+ </clipPath>
51
+ </defs>
52
+
53
+ <rect x="-12" y="-12" width="48" height="48" fill="transparent"/>
54
+
55
+ <g id="body-js">
56
+ <g id="breath-js">
57
+ <g id="edge-system">
58
+ <use class="edge-contact" href="#cloud-shape" fill="none" stroke="#7d8aa7" stroke-width="1.00" stroke-linejoin="round" transform="translate(0 .18)" filter="url(#edge-blur)"/>
59
+ <use class="edge-rim-soft" href="#cloud-shape" fill="none" stroke="#7A9DFF" stroke-width=".84" stroke-linejoin="round" filter="url(#edge-blur)"/>
60
+ <use class="edge-rim-tight" href="#cloud-shape" fill="none" stroke="#aab3c6" stroke-width=".38" stroke-linejoin="round"/>
61
+ </g>
62
+ <g filter="url(#drop)">
63
+ <use href="#cloud-shape" fill="url(#body-grad)"/>
64
+ <rect x="1" y="2" width="22" height="11" fill="url(#hi-grad)" clip-path="url(#cloud-clip)"/>
65
+ </g>
66
+ </g>
67
+ </g>
68
+ <g id="eyes-js">
69
+ <g id="blink-js">
70
+ <rect id="eye-l" class="eye" x="6.65" y="9.65" width="2.2" height="4.65" rx="1.1" ry="1.1" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
71
+ <rect id="eye-r" class="eye" x="11.05" y="9.65" width="2.2" height="4.65" rx="1.1" ry="1.1" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
72
+ </g>
73
+ </g>
74
+ <g id="__cloudling-export-shims" opacity="0" pointer-events="none" style="display:none">
75
+ <g id="offset-readout"></g>
76
+ <g id="scale-readout"></g>
77
+ </g>
78
+
79
+ <script type="application/ecmascript"><![CDATA[
80
+ const svg = document.getElementById("cloudling");
81
+ const eyes = document.getElementById("eyes-js");
82
+ const body = document.getElementById("breath-js");
83
+ const eyeGrad = document.getElementById("eye-grad");
84
+ const eyeL = document.getElementById("eye-l");
85
+ const eyeR = document.getElementById("eye-r");
86
+ const readout = document.getElementById("offset-readout");
87
+ const scaleReadout = document.getElementById("scale-readout");
88
+
89
+ const face = { x: 9.95, y: 11.975 };
90
+ const EYE_BASE = {
91
+ l: { x: 6.65, y: 9.65, h: 4.65, rx: 1.1 },
92
+ r: { x: 11.05, y: 9.65, h: 4.65, rx: 1.1 },
93
+ };
94
+ const params = {
95
+ eyeMax: 2.05,
96
+ yClamp: 0.85,
97
+ maxRotDeg: 13,
98
+ cloudLag: 0.20,
99
+ scaleLow: 0.96,
100
+ breathPeriod: 5.0,
101
+ distNear: 6,
102
+ distFar: 20,
103
+ distMaxScale: 1.15,
104
+ distRecenter: 0.5,
105
+ flowPeriod: 5.5,
106
+ flowAmp: 4,
107
+ blinkInterval: 6.0,
108
+ blinkDur: 0.16,
109
+ eyeTrack: 0.06,
110
+ recenter: 0.15,
111
+ };
112
+ let pointerInside = false;
113
+ let pointer = { ...face };
114
+ let current = { x: 0, y: 0 };
115
+ let target = { x: 0, y: 0 };
116
+ let cloudRotate = 0;
117
+ let currentDistScale = 1.0;
118
+ let lastT = performance.now();
119
+ const startT = performance.now();
120
+ let lowPowerPaused = false;
121
+ let lowPowerPausedAt = 0;
122
+ let lowPowerPausedTotal = 0;
123
+ let rafId = 0;
124
+ let nextBlinkT = 3 + Math.random() * 2;
125
+ let blinkActive = false;
126
+ let blinkStartT = 0;
127
+
128
+ function scheduleLoop() {
129
+ if (!lowPowerPaused && !rafId) rafId = requestAnimationFrame(tick);
130
+ }
131
+
132
+ window.__clawdSetLowPowerPaused = paused => {
133
+ const next = !!paused;
134
+ if (lowPowerPaused === next) return;
135
+ lowPowerPaused = next;
136
+ if (next) {
137
+ lowPowerPausedAt = performance.now();
138
+ if (rafId) cancelAnimationFrame(rafId);
139
+ rafId = 0;
140
+ return;
141
+ }
142
+ if (lowPowerPausedAt) lowPowerPausedTotal += performance.now() - lowPowerPausedAt;
143
+ lowPowerPausedAt = 0;
144
+ lastT = performance.now();
145
+ scheduleLoop();
146
+ };
147
+
148
+ function clamp(v, min, max) {
149
+ return Math.max(min, Math.min(max, v));
150
+ }
151
+
152
+ function svgPointFromEvent(e) {
153
+ const r = svg.getBoundingClientRect();
154
+ return {
155
+ x: (e.clientX - r.left) * (48 / r.width) - 12,
156
+ y: (e.clientY - r.top) * (48 / r.height) - 12,
157
+ };
158
+ }
159
+
160
+ function updateTarget() {
161
+ if (!pointerInside) {
162
+ target.x = 0;
163
+ target.y = 0;
164
+ return;
165
+ }
166
+ const dx = pointer.x - face.x;
167
+ const dy = pointer.y - face.y;
168
+ const dist = Math.hypot(dx, dy);
169
+ if (dist < 0.01) {
170
+ target.x = 0;
171
+ target.y = 0;
172
+ return;
173
+ }
174
+ const sat = Math.tanh(dist / 6);
175
+ target.x = (dx / dist) * sat * params.eyeMax;
176
+ target.y = clamp((dy / dist) * sat * params.eyeMax, -params.eyeMax * params.yClamp, params.eyeMax * params.yClamp);
177
+ }
178
+
179
+ function tick(now) {
180
+ rafId = 0;
181
+ if (lowPowerPaused) return;
182
+ const dt = Math.min(0.05, (now - lastT) / 1000);
183
+ lastT = now;
184
+ const t = (now - startT - lowPowerPausedTotal) / 1000;
185
+ updateTarget();
186
+ const eyeTime = pointerInside ? params.eyeTrack : params.recenter;
187
+ const eyeRate = 1 - Math.exp(-dt / eyeTime);
188
+ current.x += (target.x - current.x) * eyeRate;
189
+ current.y += (target.y - current.y) * eyeRate;
190
+
191
+ const maxRot = params.maxRotDeg * Math.PI / 180;
192
+ const targetRot = (current.x / Math.max(params.eyeMax, 0.01)) * maxRot;
193
+ cloudRotate += (targetRot - cloudRotate) * params.cloudLag;
194
+
195
+ const phase = (Math.cos(2 * Math.PI * t / params.breathPeriod) + 1) / 2;
196
+ const breathScale = params.scaleLow + (1 - params.scaleLow) * phase;
197
+ let targetDistScale = 1.0;
198
+ if (pointerInside) {
199
+ const dx = pointer.x - face.x;
200
+ const dy = pointer.y - face.y;
201
+ const dist = Math.hypot(dx, dy);
202
+ if (dist > params.distNear) {
203
+ const t01 = Math.min((dist - params.distNear) / Math.max(params.distFar - params.distNear, 0.01), 1);
204
+ targetDistScale = 1.0 + (params.distMaxScale - 1.0) * t01;
205
+ }
206
+ }
207
+ const distRate = 1 - Math.exp(-dt / params.distRecenter);
208
+ currentDistScale += (targetDistScale - currentDistScale) * distRate;
209
+ const finalScale = breathScale * currentDistScale;
210
+ const angleDeg = cloudRotate * 180 / Math.PI;
211
+ body.setAttribute(
212
+ "transform",
213
+ `translate(12 12) rotate(${angleDeg.toFixed(3)}) scale(${finalScale.toFixed(4)}) translate(-12 -12)`
214
+ );
215
+ const eyeScale = currentDistScale;
216
+ eyes.setAttribute(
217
+ "transform",
218
+ `translate(${current.x.toFixed(3)} ${current.y.toFixed(3)}) translate(${face.x} ${face.y}) scale(${eyeScale.toFixed(4)}) translate(${-face.x} ${-face.y})`
219
+ );
220
+ applyBlink(t);
221
+ const flowOffset = Math.sin(2 * Math.PI * t / params.flowPeriod) * params.flowAmp;
222
+ eyeGrad.setAttribute("y1", (3 + flowOffset).toFixed(2));
223
+ eyeGrad.setAttribute("y2", (21 + flowOffset).toFixed(2));
224
+ readout.textContent = `offset: ${current.x.toFixed(2)}, ${current.y.toFixed(2)}`;
225
+ scaleReadout.textContent = `scale: ${finalScale.toFixed(3)}, rot: ${angleDeg.toFixed(1)}deg`;
226
+ scheduleLoop();
227
+ }
228
+
229
+ function getBlinkScale(t) {
230
+ if (!blinkActive && t > nextBlinkT) {
231
+ blinkActive = true;
232
+ blinkStartT = t;
233
+ }
234
+ if (blinkActive) {
235
+ const d = t - blinkStartT;
236
+ const half = params.blinkDur / 2;
237
+ if (d < half) return 1 - 0.94 * (d / half);
238
+ if (d < params.blinkDur) return 0.06 + 0.94 * ((d - half) / half);
239
+ blinkActive = false;
240
+ nextBlinkT = t + params.blinkInterval * (0.8 + Math.random() * 0.4);
241
+ }
242
+ return 1;
243
+ }
244
+
245
+ function setBlinkRect(rect, base, scale) {
246
+ const h = Math.max(base.h * scale, 0.15);
247
+ const y = base.y + (base.h - h) / 2;
248
+ const rx = Math.min(base.rx, h / 2);
249
+ rect.setAttribute("height", h.toFixed(3));
250
+ rect.setAttribute("y", y.toFixed(3));
251
+ rect.setAttribute("rx", rx.toFixed(3));
252
+ rect.setAttribute("ry", rx.toFixed(3));
253
+ }
254
+
255
+ function applyBlink(t) {
256
+ const scale = getBlinkScale(t);
257
+ setBlinkRect(eyeL, EYE_BASE.l, scale);
258
+ setBlinkRect(eyeR, EYE_BASE.r, scale);
259
+ }
260
+
261
+ window.addEventListener("pointermove", e => {
262
+ const r = svg.getBoundingClientRect();
263
+ const inside = e.clientX >= r.left && e.clientX <= r.right
264
+ && e.clientY >= r.top && e.clientY <= r.bottom;
265
+ pointerInside = inside;
266
+ if (inside) pointer = svgPointFromEvent(e);
267
+ });
268
+ svg.addEventListener("pointerleave", () => {
269
+ pointerInside = false;
270
+ });
271
+ window.__cloudlingSetPointer = payload => {
272
+ if (!payload || !Number.isFinite(payload.x) || !Number.isFinite(payload.y)) return;
273
+ pointer.x = payload.x;
274
+ pointer.y = payload.y;
275
+ pointerInside = !!payload.inside;
276
+ };
277
+ scheduleLoop();
278
+ ]]></script>
279
+ </svg>
@@ -0,0 +1,328 @@
1
+ <svg id="cloudling" xmlns="http://www.w3.org/2000/svg" viewBox="-6 -6 36 36" preserveAspectRatio="xMidYMid meet">
2
+ <style><![CDATA[
3
+ .v {
4
+ text-align: right;
5
+ font: 600 10px ui-monospace, SFMono-Regular, Menlo, monospace;
6
+ color: #7A9DFF;
7
+ }
8
+ .edge-rim-tight { stroke-opacity: .9; }
9
+ .edge-rim-soft { stroke-opacity: .75; }
10
+ .edge-contact { stroke-opacity: .9; }
11
+ @media (prefers-color-scheme: light) {
12
+ .v { color: #3941FF; }
13
+ .edge-rim-tight { stroke-opacity: .95; }
14
+ .edge-rim-soft { stroke-opacity: .85; }
15
+ .edge-contact { stroke-opacity: .95; }
16
+ .cloud-drop-shadow { flood-opacity: .13; }
17
+ .food-cloud-shadow { flood-opacity: .28; flood-color: #5060FF; }
18
+ .food-cloud > path {
19
+ stroke: #5870E8 !important;
20
+ stroke-width: 1.2 !important;
21
+ stroke-opacity: .9 !important;
22
+ vector-effect: non-scaling-stroke !important;
23
+ }
24
+ }
25
+ ]]></style>
26
+ <defs>
27
+ <linearGradient id="body-grad" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
28
+ <stop offset="0" stop-color="#93c5fd"/>
29
+ <stop offset="0.5" stop-color="#60a5fa"/>
30
+ <stop offset="1" stop-color="#3b82f6"/>
31
+ </linearGradient>
32
+ <linearGradient id="eye-grad" x1="12" y1="3" x2="12" y2="21" gradientUnits="userSpaceOnUse">
33
+ <stop offset="0" stop-color="#B1A7FF"/>
34
+ <stop offset="0.5" stop-color="#7A9DFF"/>
35
+ <stop offset="1" stop-color="#3941FF"/>
36
+ </linearGradient>
37
+ <radialGradient id="hi-grad" cx="0.45" cy="0.25" r="0.55">
38
+ <stop offset="0" stop-color="#93c5fd" stop-opacity="0.9"/>
39
+ <stop offset="1" stop-color="#93c5fd" stop-opacity="0"/>
40
+ </radialGradient>
41
+ <filter id="drop" x="-40%" y="-40%" width="180%" height="180%">
42
+ <feDropShadow class="cloud-drop-shadow" dx="0" dy="0.55" stdDeviation="0.72" flood-color="#3941FF" flood-opacity="0.17"/>
43
+ </filter>
44
+ <filter id="edge-blur" x="-40%" y="-40%" width="180%" height="180%">
45
+ <feGaussianBlur stdDeviation="0.16"/>
46
+ </filter>
47
+ <path id="cloud-shape" d="M9.064 3.344a4.578 4.578 0 012.285-.312c1 .115 1.891.54 2.673 1.275.01.01.024.017.037.021a.09.09 0 00.043 0 4.55 4.55 0 013.046.275l.047.022.116.057a4.581 4.581 0 012.188 2.399c.209.51.313 1.041.315 1.595a4.24 4.24 0 01-.134 1.223.123.123 0 00.03.115c.594.607.988 1.33 1.183 2.17.289 1.425-.007 2.71-.887 3.854l-.136.166a4.548 4.548 0 01-2.201 1.388.123.123 0 00-.081.076c-.191.551-.383 1.023-.74 1.494-.9 1.187-2.222 1.846-3.711 1.838-1.187-.006-2.239-.44-3.157-1.302a.107.107 0 00-.105-.024c-.388.125-.78.143-1.204.138a4.441 4.441 0 01-1.945-.466 4.544 4.544 0 01-1.61-1.335c-.152-.202-.303-.392-.414-.617a5.81 5.81 0 01-.37-.961 4.582 4.582 0 01-.014-2.298.124.124 0 00.006-.056.085.085 0 00-.027-.048 4.467 4.467 0 01-1.034-1.651 3.896 3.896 0 01-.251-1.192 5.189 5.189 0 01.141-1.6c.337-1.112.982-1.985 1.933-2.618.212-.141.413-.251.601-.33.215-.089.43-.164.646-.227a.098.098 0 00.065-.066 4.51 4.51 0 01.829-1.615 4.535 4.535 0 011.837-1.388z"/>
48
+ <clipPath id="cloud-clip">
49
+ <use href="#cloud-shape"/>
50
+ </clipPath>
51
+ </defs>
52
+
53
+ <rect x="-12" y="-12" width="48" height="48" fill="transparent"/>
54
+
55
+ <g id="pose-js">
56
+ <g id="body-js">
57
+ <g id="breath-js">
58
+ <g id="edge-system">
59
+ <use id="edge-contact" class="edge-contact" href="#cloud-shape" fill="none" stroke="#7d8aa7" stroke-width="1.00" stroke-linejoin="round" transform="translate(0 .18)" filter="url(#edge-blur)"/>
60
+ <use id="edge-soft" class="edge-rim-soft" href="#cloud-shape" fill="none" stroke="#7A9DFF" stroke-width=".84" stroke-linejoin="round" filter="url(#edge-blur)"/>
61
+ <use id="edge-tight" class="edge-rim-tight" href="#cloud-shape" fill="none" stroke="#aab3c6" stroke-width=".38" stroke-linejoin="round"/>
62
+ </g>
63
+ <g filter="url(#drop)">
64
+ <use href="#cloud-shape" fill="url(#body-grad)"/>
65
+ <rect x="1" y="2" width="22" height="11" fill="url(#hi-grad)" clip-path="url(#cloud-clip)"/>
66
+ </g>
67
+ </g>
68
+ </g>
69
+ <g id="eyes-js">
70
+ <g id="blink-js">
71
+ <rect id="eye-l" class="eye" x="6.65" y="9.65" width="2.2" height="4.65" rx="1.1" ry="1.1" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
72
+ <rect id="eye-r" class="eye" x="11.05" y="9.65" width="2.2" height="4.65" rx="1.1" ry="1.1" fill="url(#eye-grad)" stroke="#ffffff" stroke-width="0.08" stroke-opacity="0.7"/>
73
+ </g>
74
+ </g>
75
+ </g>
76
+ <g id="__cloudling-export-shims" opacity="0" pointer-events="none" style="display:none">
77
+ <g id="eye-readout"></g>
78
+ <g id="pose-readout"></g>
79
+ <g id="shake-readout"></g>
80
+ </g>
81
+
82
+ <script type="application/ecmascript"><![CDATA[
83
+ const svg = document.getElementById("cloudling");
84
+ const pose = document.getElementById("pose-js");
85
+ const eyes = document.getElementById("eyes-js");
86
+ const body = document.getElementById("breath-js");
87
+ const eyeGrad = document.getElementById("eye-grad");
88
+ const eyeL = document.getElementById("eye-l");
89
+ const eyeR = document.getElementById("eye-r");
90
+ const edgeContact = document.getElementById("edge-contact");
91
+ const edgeSoft = document.getElementById("edge-soft");
92
+ const edgeTight = document.getElementById("edge-tight");
93
+ const poseReadout = document.getElementById("pose-readout");
94
+ const shakeReadout = document.getElementById("shake-readout");
95
+ const eyeReadout = document.getElementById("eye-readout");
96
+
97
+ const MINI_EYE_BASE = {
98
+ l: { cx: 7.75, cy: 11.975, w: 2.20, h: 4.65, rx: 1.10 },
99
+ r: { cx: 12.15, cy: 11.975, w: 2.20, h: 4.65, rx: 1.10 },
100
+ };
101
+ const IDLE_EYE_BASE = {
102
+ l: { cx: 9.00, cy: 12.00, w: 2.60, h: 5.00, rx: 1.30 },
103
+ r: { cx: 15.00, cy: 12.00, w: 2.60, h: 5.00, rx: 1.30 },
104
+ };
105
+ const face = { x: 12.00, y: 12.00 };
106
+ const params = {
107
+ settleTx: -0.22,
108
+ settleTy: -0.04,
109
+ settleScale: 1.012,
110
+ settleRot: -0.65,
111
+ eyeReturnDur: 0.24,
112
+ idleEyeMax: 0.50,
113
+ idleYClamp: 1.00,
114
+ idleRecenter: 0.45,
115
+ duangDelay: 0.10,
116
+ duangDur: 1.12,
117
+ duangPower: 1.16,
118
+ duangCycles: 4.80,
119
+ duangTravel: 0.33,
120
+ duangLift: 0.10,
121
+ duangRot: 4.20,
122
+ duangSquash: 0.048,
123
+ breath: 0.008,
124
+ rimPower: 1.30,
125
+ flowPeriod: 4.8,
126
+ flowAmp: 4.8,
127
+ blinkInterval: 5.2,
128
+ blinkDur: 0.14,
129
+ };
130
+ let startT = performance.now();
131
+ let lastFrameT = 0;
132
+ let nextBlinkT = 2.4 + Math.random() * 1.4;
133
+ let blinkActive = false;
134
+ let blinkStartT = 0;
135
+ let lastState = null;
136
+ let pointerInside = false;
137
+ let pointer = { ...face };
138
+ let idleEye = { x: 0, y: 0 };
139
+
140
+ function clamp(v, min = 0, max = 1) {
141
+ return Math.max(min, Math.min(max, v));
142
+ }
143
+
144
+ function lerp(a, b, t) {
145
+ return a + (b - a) * t;
146
+ }
147
+
148
+ function smoothstep(edge0, edge1, x) {
149
+ const t = clamp((x - edge0) / Math.max(edge1 - edge0, 0.0001));
150
+ return t * t * (3 - 2 * t);
151
+ }
152
+
153
+ function easeOutCubic(t) {
154
+ return 1 - Math.pow(1 - clamp(t), 3);
155
+ }
156
+
157
+ function duangWave(t) {
158
+ const u = clamp((t - params.duangDelay) / Math.max(params.duangDur, 0.01));
159
+ if (u <= 0 || u >= 1) return 0;
160
+ const envelope = Math.pow(1 - u, 1.35);
161
+ return Math.sin(u * Math.PI * params.duangCycles) * envelope * params.duangPower;
162
+ }
163
+
164
+ function pointerToSvg(e) {
165
+ const r = svg.getBoundingClientRect();
166
+ const x = -12 + ((e.clientX - r.left) / Math.max(r.width, 1)) * 48;
167
+ const y = -12 + ((e.clientY - r.top) / Math.max(r.height, 1)) * 48;
168
+ pointer = { x, y };
169
+ pointerInside = true;
170
+ }
171
+
172
+ function idleEyeTarget() {
173
+ const dx = pointer.x - face.x;
174
+ const dy = pointer.y - face.y;
175
+ const dist = Math.hypot(dx, dy);
176
+ if (dist < 0.001) return { x: 0, y: 0 };
177
+ const sat = Math.tanh(dist / 6);
178
+ return {
179
+ x: (dx / dist) * sat * params.idleEyeMax,
180
+ y: clamp((dy / dist) * sat * params.idleEyeMax, -params.idleEyeMax * params.idleYClamp, params.idleEyeMax * params.idleYClamp),
181
+ };
182
+ }
183
+
184
+ function updateIdleEye(dt) {
185
+ const target = pointerInside ? idleEyeTarget() : { x: 0, y: 0 };
186
+ if (pointerInside) {
187
+ idleEye = target;
188
+ } else {
189
+ const recenterRate = 1 - Math.exp(-dt / Math.max(params.idleRecenter, 0.001));
190
+ idleEye.x += (target.x - idleEye.x) * recenterRate;
191
+ idleEye.y += (target.y - idleEye.y) * recenterRate;
192
+ }
193
+ return idleEye;
194
+ }
195
+
196
+ function stateAt(t, dt) {
197
+ const idle = updateIdleEye(dt);
198
+ const eyeReturn = smoothstep(0, params.eyeReturnDur, t);
199
+ const bodyWake = easeOutCubic(clamp(t / 0.30));
200
+ const spring = duangWave(t);
201
+ const hit = Math.abs(spring);
202
+ const hold = Math.sin(2 * Math.PI * t / 3.9);
203
+ const live = smoothstep(0.65, 1.25, t);
204
+ const bodyStart = 1 - bodyWake;
205
+ const poseTx = params.settleTx - bodyStart * 0.28 + spring * params.duangTravel + live * Math.sin(2 * Math.PI * t / 3.1 + 0.8) * 0.018;
206
+ const poseTy = params.settleTy - hit * params.duangLift + hold * 0.022 * live;
207
+ const poseRot = params.settleRot - bodyStart * 1.15 + spring * params.duangRot + hold * 0.12 * live;
208
+ const sx = params.settleScale + hit * params.duangSquash;
209
+ const sy = params.settleScale - hit * params.duangSquash * 0.72;
210
+ const breathScale = 1 + Math.sin(2 * Math.PI * t / 4.8) * params.breath * live;
211
+ const eyeTx = idle.x * eyeReturn;
212
+ const eyeTy = idle.y * eyeReturn;
213
+ const flowOffset = Math.sin(2 * Math.PI * t / params.flowPeriod) * params.flowAmp;
214
+ return { t, poseTx, poseTy, poseRot, sx, sy, breathScale, eyeTx, eyeTy, eyeMorph: eyeReturn, idleEyeX: idle.x, idleEyeY: idle.y, flowOffset, spring };
215
+ }
216
+
217
+ function tick(now) {
218
+ const t = (now - startT) / 1000;
219
+ const dt = Math.min(0.05, Math.max(0.001, t - lastFrameT));
220
+ lastFrameT = t;
221
+ renderFrame(t, dt);
222
+ requestAnimationFrame(tick);
223
+ }
224
+
225
+ function renderFrame(t, dt = 1 / 60) {
226
+ const s = stateAt(Math.max(0, t), dt);
227
+ pose.setAttribute(
228
+ "transform",
229
+ `translate(${s.poseTx.toFixed(3)} ${s.poseTy.toFixed(3)}) translate(12 12) rotate(${s.poseRot.toFixed(3)}) scale(${s.sx.toFixed(4)} ${s.sy.toFixed(4)}) translate(-12 -12)`
230
+ );
231
+ body.setAttribute(
232
+ "transform",
233
+ `translate(12 12) scale(${s.breathScale.toFixed(4)}) translate(-12 -12)`
234
+ );
235
+ eyes.setAttribute("transform", `translate(${s.eyeTx.toFixed(3)} ${s.eyeTy.toFixed(3)})`);
236
+ applyEyes(s.t, s.eyeMorph);
237
+ applyEdgePower();
238
+ eyeGrad.setAttribute("y1", (3 + s.flowOffset).toFixed(2));
239
+ eyeGrad.setAttribute("y2", (21 + s.flowOffset).toFixed(2));
240
+ updateReadouts(s);
241
+ lastState = s;
242
+ return s;
243
+ }
244
+
245
+ function getBlinkScale(t) {
246
+ if (!blinkActive && t > nextBlinkT) {
247
+ blinkActive = true;
248
+ blinkStartT = t;
249
+ }
250
+ if (blinkActive) {
251
+ const d = t - blinkStartT;
252
+ const half = params.blinkDur / 2;
253
+ if (d < half) return 1 - 0.94 * (d / half);
254
+ if (d < params.blinkDur) return 0.06 + 0.94 * ((d - half) / half);
255
+ blinkActive = false;
256
+ nextBlinkT = t + params.blinkInterval * (0.8 + Math.random() * 0.4);
257
+ }
258
+ return 1;
259
+ }
260
+
261
+ function setEyeRect(rect, miniBase, idleBase, blinkScale, morph) {
262
+ const cx = lerp(miniBase.cx, idleBase.cx, morph);
263
+ const cy = lerp(miniBase.cy, idleBase.cy, morph);
264
+ const w = lerp(miniBase.w, idleBase.w, morph);
265
+ const baseH = lerp(miniBase.h, idleBase.h, morph);
266
+ const h = Math.max(baseH * blinkScale, 0.15);
267
+ const x = cx - w / 2;
268
+ const y = cy - h / 2;
269
+ const rx = Math.min(lerp(miniBase.rx, idleBase.rx, morph), w / 2, h / 2);
270
+ rect.setAttribute("x", x.toFixed(3));
271
+ rect.setAttribute("width", w.toFixed(3));
272
+ rect.setAttribute("height", h.toFixed(3));
273
+ rect.setAttribute("y", y.toFixed(3));
274
+ rect.setAttribute("rx", rx.toFixed(3));
275
+ rect.setAttribute("ry", rx.toFixed(3));
276
+ }
277
+
278
+ function applyEyes(t, morph) {
279
+ const blinkScale = getBlinkScale(t);
280
+ setEyeRect(eyeL, MINI_EYE_BASE.l, IDLE_EYE_BASE.l, blinkScale, morph);
281
+ setEyeRect(eyeR, MINI_EYE_BASE.r, IDLE_EYE_BASE.r, blinkScale, morph);
282
+ }
283
+
284
+ function applyEdgePower() {
285
+ edgeContact.style.strokeOpacity = (0.08 * params.rimPower).toFixed(3);
286
+ edgeSoft.style.strokeOpacity = (0.06 * params.rimPower).toFixed(3);
287
+ edgeTight.style.strokeOpacity = (0.08 * params.rimPower).toFixed(3);
288
+ }
289
+
290
+ function updateReadouts(s) {
291
+ poseReadout.textContent = `pose: tx ${params.settleTx.toFixed(2)}, scale ${params.settleScale.toFixed(3)}, rot ${params.settleRot.toFixed(2)}deg`;
292
+ shakeReadout.textContent = `duang: power ${params.duangPower.toFixed(2)} / ${params.duangDur.toFixed(2)}s / cycles ${params.duangCycles.toFixed(2)} / now ${s.spring.toFixed(2)}`;
293
+ eyeReadout.textContent = `eyes: mini 2.2x4.65 gap 4.4 -> idle 2.6x5 gap 6 / morph ${s.eyeMorph.toFixed(2)} / offset ${s.idleEyeX.toFixed(2)}, ${s.idleEyeY.toFixed(2)}`;
294
+ }
295
+
296
+ renderFrame(0);
297
+
298
+ window.__miniPeekDebug = {
299
+ renderAt(seconds) {
300
+ return renderFrame(Number(seconds) || 0);
301
+ },
302
+ getState() {
303
+ return lastState;
304
+ },
305
+ getParams() {
306
+ return { ...params };
307
+ },
308
+ };
309
+
310
+ function restart(now = performance.now()) {
311
+ startT = now;
312
+ lastFrameT = 0;
313
+ nextBlinkT = 2.4 + Math.random() * 1.4;
314
+ blinkActive = false;
315
+ renderFrame(0);
316
+ }
317
+
318
+ svg.addEventListener("pointerenter", e => {
319
+ pointerToSvg(e);
320
+ restart();
321
+ });
322
+ svg.addEventListener("pointermove", pointerToSvg);
323
+ svg.addEventListener("pointerleave", () => {
324
+ pointerInside = false;
325
+ });
326
+ requestAnimationFrame(tick);
327
+ ]]></script>
328
+ </svg>