@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,292 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="stage" xmlns="http://www.w3.org/2000/svg" width="880" height="720" viewBox="-32 -24 88 72" preserveAspectRatio="xMidYMid meet">
3
+ <g id="__cloudling-export-shims" opacity="0" pointer-events="none" style="display:none">
4
+ <g id="phase-label"></g>
5
+ <g id="play"></g>
6
+ <g id="scrubber"></g>
7
+ <g id="time-label"></g>
8
+ </g>
9
+ <script type="application/ecmascript"><![CDATA[
10
+ const CLOUD_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";
11
+
12
+ const stage = document.getElementById('stage');
13
+ const scrubber = document.getElementById('scrubber');
14
+ const timeLabel = document.getElementById('time-label');
15
+ const phaseLabel = document.getElementById('phase-label');
16
+ const playButton = document.getElementById('play');
17
+
18
+ const P = {
19
+ cycle: 4.55,
20
+ cardW: 6.8,
21
+ cardH: 8.6,
22
+ events: [
23
+ { start: .36, end: 1.22, slot: 0, yNudge: -.10 },
24
+ { start: 1.36, end: 2.22, slot: 1, yNudge: .55 },
25
+ { start: 2.36, end: 3.22, slot: 2, yNudge: .18 },
26
+ ],
27
+ compactStart: 3.36,
28
+ compactEnd: 3.96,
29
+ };
30
+
31
+ function clamp01(t) { return Math.max(0, Math.min(1, t)); }
32
+ function lerp(a, b, t) { return a + (b - a) * t; }
33
+ function progress(t, a, b) { return clamp01((t - a) / (b - a)); }
34
+ function easeInOut(t) { return t < .5 ? 4*t*t*t : 1 - Math.pow(-2*t + 2, 3) / 2; }
35
+ function smoothstep(a, b, t) {
36
+ const x = progress(t, a, b);
37
+ return x * x * (3 - 2 * x);
38
+ }
39
+ function cubic(a, b, c, d, t) {
40
+ const u = 1 - t;
41
+ return u*u*u*a + 3*u*u*t*b + 3*u*t*t*c + t*t*t*d;
42
+ }
43
+ function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
44
+
45
+ function commonDefs() {
46
+ return `
47
+ <linearGradient id="body-grad" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
48
+ <stop offset="0" stop-color="#fff"/>
49
+ <stop offset=".54" stop-color="#e0f2fe"/>
50
+ <stop offset="1" stop-color="#bae6fd"/>
51
+ </linearGradient>
52
+ <linearGradient id="eye-grad" x1="12" y1="8" x2="12" y2="16" gradientUnits="userSpaceOnUse">
53
+ <stop offset="0" stop-color="#B1A7FF"/>
54
+ <stop offset=".55" stop-color="#7A9DFF"/>
55
+ <stop offset="1" stop-color="#3941FF"/>
56
+ </linearGradient>
57
+ <radialGradient id="hi-grad" cx=".45" cy=".25" r=".55">
58
+ <stop offset="0" stop-color="#fff" stop-opacity=".9"/>
59
+ <stop offset="1" stop-color="#fff" stop-opacity="0"/>
60
+ </radialGradient>
61
+ <filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
62
+ <feDropShadow dx="0" dy=".65" stdDeviation=".8" flood-color="#3941FF" flood-opacity=".18"/>
63
+ </filter>
64
+ <filter id="small-shadow" x="-70%" y="-70%" width="240%" height="240%">
65
+ <feDropShadow dx="0" dy=".42" stdDeviation=".62" flood-color="#101524" flood-opacity=".56"/>
66
+ </filter>
67
+ <filter id="edge-blur" x="-50%" y="-50%" width="200%" height="200%">
68
+ <feGaussianBlur stdDeviation=".16"/>
69
+ </filter>
70
+ <filter id="glow" x="-80%" y="-80%" width="260%" height="260%">
71
+ <feGaussianBlur stdDeviation=".45"/>
72
+ </filter>
73
+ <path id="cloud-shape" d="${CLOUD_D}"/>
74
+ <clipPath id="cloud-clip"><use href="#cloud-shape"/></clipPath>
75
+ `;
76
+ }
77
+
78
+ function slotPos(slot) {
79
+ return {
80
+ x: 17.55 + slot * .46,
81
+ y: 14.65 + slot * .54,
82
+ };
83
+ }
84
+
85
+ function orbitPoint(ev, t) {
86
+ const u = progress(t, ev.start, ev.end);
87
+ const e = easeInOut(u);
88
+ const end = slotPos(ev.slot);
89
+ const x = cubic(-8.6, -3.6, 9.5, end.x, e);
90
+ const y = cubic(7.2 + ev.yNudge, 7.4 + ev.yNudge, 17.1 + ev.yNudge, end.y, e);
91
+ return { x, y, u };
92
+ }
93
+
94
+ function activeEvent(t) {
95
+ return P.events.find(ev => t >= ev.start && t < ev.end) ?? null;
96
+ }
97
+
98
+ function makeCard(x, y, opacity, opts = {}) {
99
+ const scale = opts.scale ?? 1;
100
+ const detail = opts.detail ?? 1;
101
+ const id = opts.id ?? 0;
102
+ const extraClass = opts.layer ?? '';
103
+ const lineSets = [
104
+ [4.0, 5.2, 3.4],
105
+ [4.8, 3.6, 4.9],
106
+ [3.5, 5.0, 3.1],
107
+ ];
108
+ const lines = lineSets[id % lineSets.length];
109
+ return `
110
+ <g class="ctx-card-group ${extraClass}" opacity="${opacity.toFixed(3)}" transform="translate(${x.toFixed(3)} ${y.toFixed(3)}) scale(${scale.toFixed(3)})" filter="url(#small-shadow)">
111
+ <rect class="ctx-card-plate" x="-.14" y="-.14" width="${(P.cardW + .28).toFixed(2)}" height="${(P.cardH + .28).toFixed(2)}" rx="1.46"/>
112
+ <rect class="ctx-card" x="0" y="0" width="${P.cardW}" height="${P.cardH}" rx="1.32" stroke-width=".42"/>
113
+ <rect class="ctx-card-tint" x=".28" y=".28" width="${(P.cardW - .56).toFixed(2)}" height="${(P.cardH - .56).toFixed(2)}" rx="1.06"/>
114
+ <rect class="ctx-card-inner" x=".48" y=".48" width="${(P.cardW - .96).toFixed(2)}" height="${(P.cardH - .96).toFixed(2)}" rx=".96" stroke-width=".16" opacity="${(.68 * detail).toFixed(3)}"/>
115
+ <rect class="ctx-line-a" x="1.28" y="1.98" width="${lines[0]}" height=".34" rx=".17" opacity="${(.96 * detail).toFixed(3)}"/>
116
+ <rect class="ctx-line-b" x="1.28" y="3.64" width="${lines[1]}" height=".30" rx=".15" opacity="${(.84 * detail).toFixed(3)}"/>
117
+ <rect class="ctx-line-c" x="1.28" y="5.24" width="${lines[2]}" height=".30" rx=".15" opacity="${(.80 * detail).toFixed(3)}"/>
118
+ <rect class="ctx-line-a" x="1.28" y="6.84" width="${(lines[1] * .68).toFixed(2)}" height=".30" rx=".15" opacity="${(.50 * detail).toFixed(3)}"/>
119
+ </g>
120
+ `;
121
+ }
122
+
123
+ function makeMovingCard(t, layer) {
124
+ const ev = activeEvent(t);
125
+ if (!ev) return '';
126
+ const p = orbitPoint(ev, t);
127
+ const fadeIn = smoothstep(ev.start, ev.start + .16, t);
128
+ const backAlpha = smoothstep(.58, .76, p.u);
129
+ const frontAlpha = 1 - smoothstep(.62, .80, p.u);
130
+ const opacity = layer === 'back' ? backAlpha * fadeIn * .78 : frontAlpha * fadeIn;
131
+ if (opacity <= .01) return '';
132
+ return makeCard(p.x, p.y, opacity, { id: ev.slot, detail: layer === 'back' ? .72 : 1, layer: `moving-${layer}` });
133
+ }
134
+
135
+ function makeStack(t) {
136
+ const compactU = progress(t, P.compactStart, P.compactEnd);
137
+ const compacting = t >= P.compactStart && t < P.compactEnd;
138
+ if (t >= P.compactEnd) return '';
139
+
140
+ const arrived = P.events.filter(ev => t >= ev.end).length;
141
+ if (arrived === 0) return '';
142
+
143
+ const op = compacting ? lerp(1, 0, smoothstep(P.compactStart + .18, P.compactEnd, t)) : 1;
144
+ const scale = compacting ? lerp(1, .76, easeInOut(compactU)) : 1;
145
+ const cx = 20.8;
146
+ const cy = 19.4;
147
+ const cards = [];
148
+ for (let i = 0; i < arrived; i++) {
149
+ const s = slotPos(i);
150
+ cards.push(makeCard(s.x, s.y, op * .82, { id: i, detail: i === arrived - 1 ? .76 : .58, layer: 'stacked-behind' }));
151
+ }
152
+ const flash = compacting ? Math.sin(progress(t, P.compactStart, P.compactStart + .34) * Math.PI) : 0;
153
+ return `
154
+ <g class="behind-stack" transform="translate(${cx.toFixed(2)} ${cy.toFixed(2)}) scale(${scale.toFixed(3)}) translate(${-cx.toFixed(2)} ${-cy.toFixed(2)})">
155
+ ${cards.join('')}
156
+ <rect x="17.15" y="14.25" width="9.8" height="12.6" rx="2.0" fill="none" stroke="#fff" stroke-width=".16" opacity="${(flash * .28).toFixed(3)}" filter="url(#glow)"/>
157
+ </g>
158
+ `;
159
+ }
160
+
161
+ function computeCloudPose(t) {
162
+ const ev = activeEvent(t);
163
+ let eyeX = 0;
164
+ let eyeY = 0;
165
+ let rot = 0;
166
+ if (ev) {
167
+ const p = orbitPoint(ev, t);
168
+ const cx = p.x + P.cardW / 2;
169
+ const cy = p.y + P.cardH / 2;
170
+ const dx = cx - 12;
171
+ const dy = cy - 12;
172
+ const d = Math.hypot(dx, dy) || 1;
173
+ const sat = Math.tanh(d / 7);
174
+ eyeX = (dx / d) * sat * .48;
175
+ eyeY = (dy / d) * sat * .32;
176
+ rot = clamp(dx * .27, -3.6, 4.2) * Math.sin(Math.PI * p.u);
177
+ } else if (t >= P.compactStart && t <= P.compactEnd) {
178
+ const u = progress(t, P.compactStart, P.compactEnd);
179
+ eyeX = .28 * (1 - u);
180
+ rot = 2.2 * Math.sin(Math.PI * u);
181
+ }
182
+ const breath = 1 + Math.sin(t * Math.PI * 2 / 3.2) * .018;
183
+ const compactDip = t >= P.compactStart && t <= P.compactEnd ? -Math.sin(progress(t, P.compactStart, P.compactEnd) * Math.PI) * .016 : 0;
184
+ return { eyeX, eyeY, rot, scale: breath + compactDip };
185
+ }
186
+
187
+ function makeCloudling(t) {
188
+ const pose = computeCloudPose(t);
189
+ const smile = smoothstep(P.compactStart + .14, P.compactStart + .34, t) * (1 - smoothstep(P.compactStart + .64, P.compactEnd + .12, t));
190
+ return `
191
+ <g class="cloudling" transform="rotate(${pose.rot.toFixed(3)} 12 12) translate(12 12) scale(${pose.scale.toFixed(4)}) translate(-12 -12)">
192
+ <g class="edge-system">
193
+ <use class="edge-contact" href="#cloud-shape" fill="none" stroke="#7d8aa7" stroke-width="1.05" stroke-linejoin="round" transform="translate(0 .18)" filter="url(#edge-blur)"/>
194
+ <use class="edge-rim-soft" href="#cloud-shape" fill="none" stroke="#7A9DFF" stroke-width=".90" stroke-linejoin="round" filter="url(#edge-blur)"/>
195
+ <use class="edge-rim-tight" href="#cloud-shape" fill="none" stroke="#aab3c6" stroke-width=".42" stroke-linejoin="round"/>
196
+ </g>
197
+ <g filter="url(#shadow)">
198
+ <use href="#cloud-shape" fill="url(#body-grad)"/>
199
+ <rect x="1" y="2" width="22" height="11" fill="url(#hi-grad)" clip-path="url(#cloud-clip)"/>
200
+ </g>
201
+ <g class="eyes" transform="translate(${pose.eyeX.toFixed(3)} ${pose.eyeY.toFixed(3)})">
202
+ <g opacity="${(1 - smile).toFixed(3)}">
203
+ <rect x="7.7" y="9.5" width="2.6" height="5" rx="1.3" fill="url(#eye-grad)" stroke="#fff" stroke-width=".08" stroke-opacity=".7"/>
204
+ <rect x="13.7" y="9.5" width="2.6" height="5" rx="1.3" fill="url(#eye-grad)" stroke="#fff" stroke-width=".08" stroke-opacity=".7"/>
205
+ </g>
206
+ <g opacity="${smile.toFixed(3)}">
207
+ <path d="M7.55 12.15 Q9 10.75 10.45 12.15" fill="none" stroke="url(#eye-grad)" stroke-width=".72" stroke-linecap="round"/>
208
+ <path d="M13.55 12.15 Q15 10.75 16.45 12.15" fill="none" stroke="url(#eye-grad)" stroke-width=".72" stroke-linecap="round"/>
209
+ </g>
210
+ </g>
211
+ </g>
212
+ `;
213
+ }
214
+
215
+ function phaseName(t) {
216
+ const ev = activeEvent(t);
217
+ if (ev) return `card ${ev.slot + 1} orbit`;
218
+ if (t >= P.compactStart && t < P.compactEnd) return 'behind compact';
219
+ if (t >= P.compactEnd) return 'idle reset';
220
+ return 'idle';
221
+ }
222
+
223
+ function renderFrame(t) {
224
+ stage.innerHTML = `
225
+ <style>
226
+ :root, svg {
227
+ --bg: #17171d;
228
+ --panel: #101018;
229
+ --stage-a: #1d2234;
230
+ --stage-b: #0d0f18;
231
+ --ink: #edeef6;
232
+ --muted: rgba(237,238,246,.66);
233
+ --accent: #B1A7FF;
234
+ --card-plate: rgba(16,22,50,.58);
235
+ --card-fill: rgba(218,226,246,.78);
236
+ --card-tint: rgba(112,139,214,.14);
237
+ --card-stroke: rgba(28,35,76,.82);
238
+ --card-inner: rgba(96,113,172,.46);
239
+ --line-a: rgba(28,35,76,.64);
240
+ --line-b: rgba(54,70,128,.50);
241
+ --line-c: rgba(72,84,132,.42);
242
+ }
243
+ .edge-rim-tight { stroke-opacity: .10; }
244
+ .edge-rim-soft { stroke-opacity: .07; }
245
+ .edge-contact { stroke-opacity: .09; }
246
+ .ctx-card-plate { fill: var(--card-plate); }
247
+ .ctx-card { fill: var(--card-fill); stroke: var(--card-stroke); }
248
+ .ctx-card-tint { fill: var(--card-tint); }
249
+ .ctx-card-inner { fill: none; stroke: var(--card-inner); }
250
+ .ctx-line-a { fill: var(--line-a); }
251
+ .ctx-line-b { fill: var(--line-b); }
252
+ .ctx-line-c { fill: var(--line-c); }
253
+ @media (prefers-color-scheme: light) {
254
+ :root, svg {--bg: #f5f6fb; --panel: #ffffff; --stage-a: #ffffff; --stage-b: #edf1fb; --ink: #2e3038; --muted: rgba(46,48,56,.62); --accent: #6B5CFF; --card-plate: rgba(52,61,110,.18); --card-fill: rgba(245,247,255,.82); --card-tint: rgba(91,121,220,.08); --card-stroke: rgba(56,68,132,.42); --card-inner: rgba(99,116,178,.34); --line-a: rgba(56,68,132,.52); --line-b: rgba(77,92,154,.40); --line-c: rgba(85,96,126,.34)}
255
+ .edge-rim-tight { stroke-opacity: .18; }
256
+ .edge-rim-soft { stroke-opacity: .12; }
257
+ .edge-contact { stroke-opacity: .75; }
258
+ }
259
+ </style>
260
+ <defs>${commonDefs()}</defs>
261
+ ${makeStack(t)}
262
+ ${makeMovingCard(t, 'back')}
263
+ ${makeCloudling(t)}
264
+ ${makeMovingCard(t, 'front')}
265
+ <g fill="#BFD0FF">
266
+ <circle cx="-3.2" cy="6.8" r=".13" opacity=".24"/>
267
+ <circle cx="29.6" cy="6.1" r=".13" opacity=".22"/>
268
+ </g>
269
+ `;
270
+ scrubber.value = t.toFixed(2);
271
+ timeLabel.textContent = `${t.toFixed(2)}s`;
272
+ phaseLabel.textContent = phaseName(t);
273
+ }
274
+
275
+ let start = performance.now();
276
+ let paused = false;
277
+ let scrubLock = false;
278
+ let pauseT = 0;
279
+
280
+ function currentTime(now) {
281
+ return ((now - start) / 1000) % P.cycle;
282
+ }
283
+
284
+ function tick(now) {
285
+ if (!paused && !scrubLock) renderFrame(currentTime(now));
286
+ requestAnimationFrame(tick);
287
+ }
288
+
289
+ renderFrame(0);
290
+ requestAnimationFrame(tick);
291
+ ]]></script>
292
+ </svg>