evalstate HF Staff commited on
Commit
bc89546
·
verified ·
1 Parent(s): d41f9bc

Prevent mcp-stateful-request animation restart overlap on pageshow/load

Browse files
Files changed (1) hide show
  1. animations/mcp-stateful-request.html +349 -0
animations/mcp-stateful-request.html ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ body {
8
+ background: transparent;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ width: 100vw;
13
+ height: 100vh;
14
+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
15
+ padding: 0;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .api-window {
20
+ background: linear-gradient(135deg, #1e1e1e 0%, #252526 100%);
21
+ border-radius: 16px;
22
+ padding: 20px;
23
+ width: 480px;
24
+ height: 460px;
25
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
26
+ overflow: hidden;
27
+ position: relative;
28
+ }
29
+
30
+ .api-header {
31
+ color: #888;
32
+ font-size: 11px;
33
+ margin-bottom: 12px;
34
+ padding-bottom: 8px;
35
+ border-bottom: 1px solid #333;
36
+ }
37
+
38
+ .direction-label {
39
+ font-size: 10px;
40
+ margin-bottom: 10px;
41
+ padding: 4px 8px;
42
+ border-radius: 4px;
43
+ display: inline-block;
44
+ }
45
+ .to-server { background: #0b93f620; color: #0b93f6; }
46
+ .to-client { background: #f5a62320; color: #f5a623; }
47
+
48
+ .single-message {
49
+ position: absolute;
50
+ top: 80px;
51
+ left: 20px;
52
+ right: 20px;
53
+ opacity: 0;
54
+ transform: scale(0.95);
55
+ }
56
+
57
+ .single-message.show {
58
+ animation: popIn 0.3s ease forwards;
59
+ }
60
+
61
+ .single-message.fade-out {
62
+ animation: popOut 0.25s ease forwards;
63
+ }
64
+
65
+ .msg-box {
66
+ padding: 16px;
67
+ border-radius: 10px;
68
+ font-size: 11px;
69
+ line-height: 1.5;
70
+ color: #d4d4d4;
71
+ }
72
+
73
+ .client-msg .msg-box {
74
+ background: linear-gradient(135deg, #0b93f615 0%, #007AFF15 100%);
75
+ border: 1px solid #0b93f640;
76
+ }
77
+
78
+ .server-msg .msg-box {
79
+ background: linear-gradient(135deg, #f5a62315 0%, #f0981915 100%);
80
+ border: 1px solid #f5a62340;
81
+ }
82
+
83
+ .json-brace { color: #d4d4d4; }
84
+ .json-key { color: #9cdcfe; }
85
+ .json-string { color: #ce9178; }
86
+ .json-bool { color: #569cd6; }
87
+
88
+ .state-indicator {
89
+ position: absolute;
90
+ bottom: 20px;
91
+ left: 20px;
92
+ right: 20px;
93
+ padding: 12px;
94
+ background: #2d2d3a;
95
+ border-radius: 8px;
96
+ font-size: 10px;
97
+ color: #888;
98
+ opacity: 0;
99
+ }
100
+
101
+ .state-indicator.show {
102
+ animation: fadeIn 0.3s ease forwards;
103
+ }
104
+ .state-indicator.fade-out {
105
+ animation: fadeOut 0.5s ease forwards;
106
+ }
107
+
108
+ .state-indicator .label {
109
+ color: #f5a623;
110
+ font-weight: 600;
111
+ margin-bottom: 4px;
112
+ }
113
+
114
+ .state-dots {
115
+ display: flex;
116
+ gap: 6px;
117
+ margin-top: 8px;
118
+ }
119
+
120
+ .state-dot {
121
+ width: 8px;
122
+ height: 8px;
123
+ border-radius: 50%;
124
+ background: #444;
125
+ }
126
+ .state-dot.active { background: #f5a623; }
127
+
128
+ @keyframes popIn {
129
+ from { opacity: 0; transform: scale(0.95); }
130
+ to { opacity: 1; transform: scale(1); }
131
+ }
132
+
133
+ @keyframes popOut {
134
+ from { opacity: 1; transform: scale(1); }
135
+ to { opacity: 0; transform: scale(0.95); }
136
+ }
137
+
138
+ @keyframes fadeIn {
139
+ from { opacity: 0; }
140
+ to { opacity: 1; }
141
+ }
142
+
143
+ @keyframes fadeOut {
144
+ from { opacity: 1; }
145
+ to { opacity: 0; }
146
+ }
147
+ </style>
148
+ </head>
149
+ <body>
150
+ <div class="api-window canvas-root">
151
+ <div class="api-header">Current: Individual Messages (Stateful)</div>
152
+
153
+ <!-- Message 1: CallToolRequest -->
154
+ <div class="single-message client-msg" id="msg1">
155
+ <div class="direction-label to-server">→ Client to Server</div>
156
+ <div class="msg-box">
157
+ <span class="json-brace">{</span><br>
158
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"tools/call"</span>,<br>
159
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
160
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"name"</span>: <span class="json-string">"deploy_app"</span>,<br>
161
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"env"</span>: <span class="json-string">"production"</span><br>
162
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
163
+ <span class="json-brace">}</span>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Message 2: ElicitationRequest -->
168
+ <div class="single-message server-msg" id="msg2">
169
+ <div class="direction-label to-client">← Server to Client</div>
170
+ <div class="msg-box">
171
+ <span class="json-brace">{</span><br>
172
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"elicitation/create"</span>,<br>
173
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
174
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"message"</span>: <span class="json-string">"Confirm deployment to production?"</span><br>
175
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
176
+ <span class="json-brace">}</span>
177
+ </div>
178
+ </div>
179
+
180
+ <!-- Message 3: ElicitationResponse -->
181
+ <div class="single-message client-msg" id="msg3">
182
+ <div class="direction-label to-server">→ Client to Server</div>
183
+ <div class="msg-box">
184
+ <span class="json-brace">{</span><br>
185
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
186
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"confirmed"</span>: <span class="json-bool">true</span><br>
187
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
188
+ <span class="json-brace">}</span>
189
+ </div>
190
+ </div>
191
+
192
+ <!-- Message 4: SamplingRequest -->
193
+ <div class="single-message server-msg" id="msg4">
194
+ <div class="direction-label to-client">← Server to Client</div>
195
+ <div class="msg-box">
196
+ <span class="json-brace">{</span><br>
197
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"sampling/createMessage"</span>,<br>
198
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
199
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"prompt"</span>: <span class="json-string">"Generate deployment summary"</span><br>
200
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
201
+ <span class="json-brace">}</span>
202
+ </div>
203
+ </div>
204
+
205
+ <!-- Message 5: SamplingResponse -->
206
+ <div class="single-message client-msg" id="msg5">
207
+ <div class="direction-label to-server">→ Client to Server</div>
208
+ <div class="msg-box">
209
+ <span class="json-brace">{</span><br>
210
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
211
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"content"</span>: <span class="json-string">"Deployed v2.1.0 to prod..."</span><br>
212
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
213
+ <span class="json-brace">}</span>
214
+ </div>
215
+ </div>
216
+
217
+ <!-- Message 6: CallToolResult -->
218
+ <div class="single-message server-msg" id="msg6">
219
+ <div class="direction-label to-client">← Server to Client</div>
220
+ <div class="msg-box">
221
+ <span class="json-brace">{</span><br>
222
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
223
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"status"</span>: <span class="json-string">"success"</span><br>
224
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
225
+ <span class="json-brace">}</span>
226
+ </div>
227
+ </div>
228
+
229
+ <!-- State indicator -->
230
+ <div class="state-indicator" id="stateBox">
231
+ <div class="label">⚠ Server must maintain state</div>
232
+ <div>Remembering: tool call, elicitation, sampling context...</div>
233
+ <div class="state-dots">
234
+ <div class="state-dot" id="dot1"></div>
235
+ <div class="state-dot" id="dot2"></div>
236
+ <div class="state-dot" id="dot3"></div>
237
+ <div class="state-dot" id="dot4"></div>
238
+ <div class="state-dot" id="dot5"></div>
239
+ <div class="state-dot" id="dot6"></div>
240
+ </div>
241
+ </div>
242
+ </div>
243
+
244
+ <script src="shared/canvas-scale.js"></script>
245
+ <script>
246
+ const messages = [
247
+ document.getElementById('msg1'),
248
+ document.getElementById('msg2'),
249
+ document.getElementById('msg3'),
250
+ document.getElementById('msg4'),
251
+ document.getElementById('msg5'),
252
+ document.getElementById('msg6')
253
+ ];
254
+ const dots = [
255
+ document.getElementById('dot1'),
256
+ document.getElementById('dot2'),
257
+ document.getElementById('dot3'),
258
+ document.getElementById('dot4'),
259
+ document.getElementById('dot5'),
260
+ document.getElementById('dot6')
261
+ ];
262
+ const stateBox = document.getElementById('stateBox');
263
+ const CYCLE_PAUSE = 3000;
264
+ const MSG_DURATION = 2500;
265
+
266
+ let timers = [];
267
+ let runId = 0;
268
+
269
+ function clearTimers() {
270
+ timers.forEach((id) => clearTimeout(id));
271
+ timers = [];
272
+ }
273
+
274
+ function schedule(fn, delay) {
275
+ const id = setTimeout(fn, delay);
276
+ timers.push(id);
277
+ return id;
278
+ }
279
+
280
+ function runAnimation(activeRunId) {
281
+ if (activeRunId !== runId) {
282
+ return;
283
+ }
284
+
285
+ // Reset
286
+ messages.forEach((m) => m.classList.remove('show', 'fade-out'));
287
+ dots.forEach((d) => d.classList.remove('active'));
288
+ stateBox.classList.remove('show', 'fade-out');
289
+
290
+ // Force reflow to ensure class removal is processed
291
+ void document.body.offsetHeight;
292
+
293
+ // Show state box
294
+ schedule(() => {
295
+ if (activeRunId !== runId) return;
296
+ stateBox.classList.add('show');
297
+ }, 200);
298
+
299
+ // Show each message one at a time
300
+ messages.forEach((msg, i) => {
301
+ const showTime = i * MSG_DURATION;
302
+
303
+ schedule(() => {
304
+ if (activeRunId !== runId) return;
305
+
306
+ // Hide previous
307
+ if (i > 0) messages[i - 1].classList.add('fade-out');
308
+ // Show current
309
+ msg.classList.add('show');
310
+ // Activate dot
311
+ dots[i].classList.add('active');
312
+ }, showTime);
313
+ });
314
+
315
+ // Fade out last message and state
316
+ const totalTime = messages.length * MSG_DURATION;
317
+ schedule(() => {
318
+ if (activeRunId !== runId) return;
319
+ messages[messages.length - 1].classList.add('fade-out');
320
+ stateBox.classList.add('fade-out');
321
+ }, totalTime);
322
+
323
+ // Restart
324
+ schedule(() => runAnimation(activeRunId), totalTime + 1500 + CYCLE_PAUSE);
325
+ }
326
+
327
+ function startAnimation() {
328
+ runId++;
329
+ clearTimers();
330
+ schedule(() => runAnimation(runId), 500);
331
+ }
332
+
333
+ if (document.readyState === 'complete') {
334
+ startAnimation();
335
+ } else {
336
+ window.addEventListener('load', startAnimation, { once: true });
337
+ }
338
+
339
+ // Restart only on bfcache restore.
340
+ window.addEventListener('pageshow', (event) => {
341
+ if (event.persisted) {
342
+ startAnimation();
343
+ }
344
+ });
345
+
346
+ scaleCanvas();
347
+ </script>
348
+ </body>
349
+ </html>