kamcio1989 commited on
Commit
f3bcc30
·
verified ·
1 Parent(s): 0a3a429

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1160 -19
index.html CHANGED
@@ -1,19 +1,1160 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MediaPipe Live Preview - Computer Vision Studio</title>
7
+
8
+ <!-- MediaPipe Libraries -->
9
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js"></script>
12
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js"></script>
13
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js"></script>
14
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/pose/pose.js"></script>
15
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/face_detection.js"></script>
16
+
17
+ <!-- Font Awesome for Icons -->
18
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
19
+
20
+ <style>
21
+ * {
22
+ margin: 0;
23
+ padding: 0;
24
+ box-sizing: border-box;
25
+ }
26
+
27
+ :root {
28
+ --primary: #4285f4;
29
+ --primary-dark: #3367d6;
30
+ --secondary: #34a853;
31
+ --accent: #fbbc05;
32
+ --danger: #ea4335;
33
+ --dark: #202124;
34
+ --dark-light: #292a2d;
35
+ --light: #ffffff;
36
+ --gray: #5f6368;
37
+ --gray-light: #e8eaed;
38
+ --gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
39
+ --shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
40
+ --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.15);
41
+ }
42
+
43
+ body {
44
+ font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
45
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
46
+ min-height: 100vh;
47
+ color: var(--dark);
48
+ overflow-x: hidden;
49
+ }
50
+
51
+ /* Animated Background */
52
+ .bg-animation {
53
+ position: fixed;
54
+ width: 100%;
55
+ height: 100%;
56
+ top: 0;
57
+ left: 0;
58
+ z-index: -1;
59
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
60
+ overflow: hidden;
61
+ }
62
+
63
+ .bg-animation::before {
64
+ content: '';
65
+ position: absolute;
66
+ width: 200%;
67
+ height: 200%;
68
+ top: -50%;
69
+ left: -50%;
70
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 1px, transparent 1px);
71
+ background-size: 50px 50px;
72
+ animation: bgMove 20s linear infinite;
73
+ }
74
+
75
+ @keyframes bgMove {
76
+ 0% { transform: translate(0, 0); }
77
+ 100% { transform: translate(50px, 50px); }
78
+ }
79
+
80
+ /* Header */
81
+ header {
82
+ background: rgba(255, 255, 255, 0.95);
83
+ backdrop-filter: blur(10px);
84
+ padding: 1rem 2rem;
85
+ box-shadow: var(--shadow);
86
+ position: sticky;
87
+ top: 0;
88
+ z-index: 1000;
89
+ animation: slideDown 0.5s ease-out;
90
+ }
91
+
92
+ @keyframes slideDown {
93
+ from {
94
+ transform: translateY(-100%);
95
+ opacity: 0;
96
+ }
97
+ to {
98
+ transform: translateY(0);
99
+ opacity: 1;
100
+ }
101
+ }
102
+
103
+ .header-content {
104
+ max-width: 1400px;
105
+ margin: 0 auto;
106
+ display: flex;
107
+ justify-content: space-between;
108
+ align-items: center;
109
+ flex-wrap: wrap;
110
+ gap: 1rem;
111
+ }
112
+
113
+ .logo {
114
+ display: flex;
115
+ align-items: center;
116
+ gap: 1rem;
117
+ font-size: 1.5rem;
118
+ font-weight: bold;
119
+ color: var(--primary);
120
+ }
121
+
122
+ .logo i {
123
+ font-size: 2rem;
124
+ background: var(--gradient);
125
+ -webkit-background-clip: text;
126
+ -webkit-text-fill-color: transparent;
127
+ }
128
+
129
+ .brand-link {
130
+ color: var(--primary);
131
+ text-decoration: none;
132
+ transition: all 0.3s ease;
133
+ font-size: 0.9rem;
134
+ opacity: 0.8;
135
+ }
136
+
137
+ .brand-link:hover {
138
+ opacity: 1;
139
+ transform: translateY(-2px);
140
+ }
141
+
142
+ .stats-bar {
143
+ display: flex;
144
+ gap: 2rem;
145
+ align-items: center;
146
+ }
147
+
148
+ .stat-item {
149
+ display: flex;
150
+ flex-direction: column;
151
+ align-items: center;
152
+ padding: 0.5rem 1rem;
153
+ background: var(--gray-light);
154
+ border-radius: 10px;
155
+ transition: all 0.3s ease;
156
+ }
157
+
158
+ .stat-item:hover {
159
+ transform: translateY(-2px);
160
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
161
+ }
162
+
163
+ .stat-value {
164
+ font-size: 1.2rem;
165
+ font-weight: bold;
166
+ color: var(--primary);
167
+ }
168
+
169
+ .stat-label {
170
+ font-size: 0.75rem;
171
+ color: var(--gray);
172
+ text-transform: uppercase;
173
+ }
174
+
175
+ /* Main Container */
176
+ .container {
177
+ max-width: 1400px;
178
+ margin: 2rem auto;
179
+ padding: 0 1rem;
180
+ }
181
+
182
+ .main-grid {
183
+ display: grid;
184
+ grid-template-columns: 300px 1fr 300px;
185
+ gap: 2rem;
186
+ animation: fadeIn 0.8s ease-out;
187
+ }
188
+
189
+ @keyframes fadeIn {
190
+ from {
191
+ opacity: 0;
192
+ transform: translateY(20px);
193
+ }
194
+ to {
195
+ opacity: 1;
196
+ transform: translateY(0);
197
+ }
198
+ }
199
+
200
+ /* Control Panels */
201
+ .control-panel {
202
+ background: rgba(255, 255, 255, 0.95);
203
+ backdrop-filter: blur(10px);
204
+ border-radius: 20px;
205
+ padding: 1.5rem;
206
+ box-shadow: var(--shadow);
207
+ height: fit-content;
208
+ animation: slideIn 0.6s ease-out;
209
+ }
210
+
211
+ @keyframes slideIn {
212
+ from {
213
+ opacity: 0;
214
+ transform: translateX(-20px);
215
+ }
216
+ to {
217
+ opacity: 1;
218
+ transform: translateX(0);
219
+ }
220
+ }
221
+
222
+ .panel-title {
223
+ font-size: 1.2rem;
224
+ font-weight: bold;
225
+ margin-bottom: 1.5rem;
226
+ color: var(--dark);
227
+ display: flex;
228
+ align-items: center;
229
+ gap: 0.5rem;
230
+ }
231
+
232
+ .panel-title i {
233
+ color: var(--primary);
234
+ }
235
+
236
+ .feature-toggle {
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: space-between;
240
+ padding: 0.75rem;
241
+ margin-bottom: 0.75rem;
242
+ background: var(--gray-light);
243
+ border-radius: 10px;
244
+ transition: all 0.3s ease;
245
+ cursor: pointer;
246
+ }
247
+
248
+ .feature-toggle:hover {
249
+ background: #dce1e6;
250
+ transform: translateX(5px);
251
+ }
252
+
253
+ .feature-toggle.active {
254
+ background: linear-gradient(135deg, #667eea20, #764ba220);
255
+ border: 1px solid var(--primary);
256
+ }
257
+
258
+ .toggle-switch {
259
+ position: relative;
260
+ width: 50px;
261
+ height: 26px;
262
+ background: var(--gray);
263
+ border-radius: 13px;
264
+ transition: all 0.3s ease;
265
+ }
266
+
267
+ .toggle-switch.active {
268
+ background: var(--primary);
269
+ }
270
+
271
+ .toggle-switch::after {
272
+ content: '';
273
+ position: absolute;
274
+ width: 22px;
275
+ height: 22px;
276
+ background: white;
277
+ border-radius: 50%;
278
+ top: 2px;
279
+ left: 2px;
280
+ transition: all 0.3s ease;
281
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
282
+ }
283
+
284
+ .toggle-switch.active::after {
285
+ left: 26px;
286
+ }
287
+
288
+ /* Video Container */
289
+ .video-container {
290
+ background: rgba(255, 255, 255, 0.95);
291
+ backdrop-filter: blur(10px);
292
+ border-radius: 20px;
293
+ padding: 1.5rem;
294
+ box-shadow: var(--shadow-lg);
295
+ position: relative;
296
+ animation: scaleIn 0.7s ease-out;
297
+ }
298
+
299
+ @keyframes scaleIn {
300
+ from {
301
+ opacity: 0;
302
+ transform: scale(0.9);
303
+ }
304
+ to {
305
+ opacity: 1;
306
+ transform: scale(1);
307
+ }
308
+ }
309
+
310
+ .video-wrapper {
311
+ position: relative;
312
+ width: 100%;
313
+ padding-bottom: 56.25%;
314
+ background: var(--dark);
315
+ border-radius: 15px;
316
+ overflow: hidden;
317
+ box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.3);
318
+ }
319
+
320
+ video, canvas {
321
+ position: absolute;
322
+ top: 0;
323
+ left: 0;
324
+ width: 100%;
325
+ height: 100%;
326
+ object-fit: cover;
327
+ border-radius: 15px;
328
+ }
329
+
330
+ canvas {
331
+ z-index: 2;
332
+ }
333
+
334
+ .video-controls {
335
+ display: flex;
336
+ justify-content: center;
337
+ gap: 1rem;
338
+ margin-top: 1.5rem;
339
+ }
340
+
341
+ .control-btn {
342
+ padding: 0.75rem 1.5rem;
343
+ border: none;
344
+ border-radius: 10px;
345
+ font-size: 1rem;
346
+ font-weight: 600;
347
+ cursor: pointer;
348
+ transition: all 0.3s ease;
349
+ display: flex;
350
+ align-items: center;
351
+ gap: 0.5rem;
352
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
353
+ }
354
+
355
+ .control-btn:hover {
356
+ transform: translateY(-2px);
357
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
358
+ }
359
+
360
+ .control-btn:active {
361
+ transform: translateY(0);
362
+ }
363
+
364
+ .btn-primary {
365
+ background: var(--primary);
366
+ color: white;
367
+ }
368
+
369
+ .btn-primary:hover {
370
+ background: var(--primary-dark);
371
+ }
372
+
373
+ .btn-secondary {
374
+ background: var(--secondary);
375
+ color: white;
376
+ }
377
+
378
+ .btn-danger {
379
+ background: var(--danger);
380
+ color: white;
381
+ }
382
+
383
+ .btn-accent {
384
+ background: var(--accent);
385
+ color: var(--dark);
386
+ }
387
+
388
+ /* Settings Panel */
389
+ .setting-item {
390
+ margin-bottom: 1.5rem;
391
+ }
392
+
393
+ .setting-label {
394
+ display: block;
395
+ margin-bottom: 0.5rem;
396
+ font-weight: 600;
397
+ color: var(--dark);
398
+ }
399
+
400
+ .slider {
401
+ width: 100%;
402
+ height: 6px;
403
+ border-radius: 3px;
404
+ background: var(--gray-light);
405
+ outline: none;
406
+ -webkit-appearance: none;
407
+ cursor: pointer;
408
+ }
409
+
410
+ .slider::-webkit-slider-thumb {
411
+ -webkit-appearance: none;
412
+ appearance: none;
413
+ width: 20px;
414
+ height: 20px;
415
+ border-radius: 50%;
416
+ background: var(--primary);
417
+ cursor: pointer;
418
+ transition: all 0.3s ease;
419
+ }
420
+
421
+ .slider::-webkit-slider-thumb:hover {
422
+ transform: scale(1.2);
423
+ box-shadow: 0 0 10px rgba(66, 133, 244, 0.5);
424
+ }
425
+
426
+ .slider-value {
427
+ display: inline-block;
428
+ margin-left: 0.5rem;
429
+ padding: 0.25rem 0.5rem;
430
+ background: var(--gray-light);
431
+ border-radius: 5px;
432
+ font-size: 0.875rem;
433
+ font-weight: 600;
434
+ }
435
+
436
+ /* Info Cards */
437
+ .info-card {
438
+ background: linear-gradient(135deg, #667eea10, #764ba210);
439
+ border: 1px solid rgba(102, 126, 234, 0.3);
440
+ border-radius: 10px;
441
+ padding: 1rem;
442
+ margin-bottom: 1rem;
443
+ }
444
+
445
+ .info-card h4 {
446
+ color: var(--primary);
447
+ margin-bottom: 0.5rem;
448
+ }
449
+
450
+ .info-card p {
451
+ font-size: 0.875rem;
452
+ color: var(--gray);
453
+ line-height: 1.5;
454
+ }
455
+
456
+ /* Loading Overlay */
457
+ .loading-overlay {
458
+ position: absolute;
459
+ top: 0;
460
+ left: 0;
461
+ width: 100%;
462
+ height: 100%;
463
+ background: rgba(0, 0, 0, 0.8);
464
+ display: flex;
465
+ flex-direction: column;
466
+ justify-content: center;
467
+ align-items: center;
468
+ border-radius: 15px;
469
+ z-index: 10;
470
+ transition: opacity 0.3s ease;
471
+ }
472
+
473
+ .loading-overlay.hidden {
474
+ opacity: 0;
475
+ pointer-events: none;
476
+ }
477
+
478
+ .spinner {
479
+ width: 60px;
480
+ height: 60px;
481
+ border: 4px solid rgba(255, 255, 255, 0.3);
482
+ border-top-color: white;
483
+ border-radius: 50%;
484
+ animation: spin 1s linear infinite;
485
+ }
486
+
487
+ @keyframes spin {
488
+ to { transform: rotate(360deg); }
489
+ }
490
+
491
+ .loading-text {
492
+ color: white;
493
+ margin-top: 1rem;
494
+ font-size: 1.1rem;
495
+ }
496
+
497
+ /* Toast Notification */
498
+ .toast {
499
+ position: fixed;
500
+ bottom: 2rem;
501
+ right: 2rem;
502
+ background: white;
503
+ padding: 1rem 1.5rem;
504
+ border-radius: 10px;
505
+ box-shadow: var(--shadow-lg);
506
+ display: flex;
507
+ align-items: center;
508
+ gap: 1rem;
509
+ transform: translateX(400px);
510
+ transition: transform 0.3s ease;
511
+ z-index: 2000;
512
+ }
513
+
514
+ .toast.show {
515
+ transform: translateX(0);
516
+ }
517
+
518
+ .toast-icon {
519
+ font-size: 1.5rem;
520
+ }
521
+
522
+ .toast.success .toast-icon {
523
+ color: var(--secondary);
524
+ }
525
+
526
+ .toast.error .toast-icon {
527
+ color: var(--danger);
528
+ }
529
+
530
+ .toast.info .toast-icon {
531
+ color: var(--primary);
532
+ }
533
+
534
+ /* Responsive Design */
535
+ @media (max-width: 1200px) {
536
+ .main-grid {
537
+ grid-template-columns: 250px 1fr;
538
+ }
539
+
540
+ .control-panel:last-child {
541
+ grid-column: 1 / -1;
542
+ display: grid;
543
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
544
+ gap: 1rem;
545
+ }
546
+ }
547
+
548
+ @media (max-width: 768px) {
549
+ .main-grid {
550
+ grid-template-columns: 1fr;
551
+ }
552
+
553
+ .header-content {
554
+ flex-direction: column;
555
+ text-align: center;
556
+ }
557
+
558
+ .stats-bar {
559
+ flex-wrap: wrap;
560
+ justify-content: center;
561
+ }
562
+
563
+ .video-controls {
564
+ flex-wrap: wrap;
565
+ }
566
+ }
567
+
568
+ /* Performance Monitor */
569
+ .performance-monitor {
570
+ position: absolute;
571
+ top: 1rem;
572
+ right: 1rem;
573
+ background: rgba(0, 0, 0, 0.7);
574
+ color: white;
575
+ padding: 0.5rem 1rem;
576
+ border-radius: 8px;
577
+ font-family: monospace;
578
+ font-size: 0.875rem;
579
+ z-index: 5;
580
+ }
581
+
582
+ .fps-counter {
583
+ color: #4ade80;
584
+ font-weight: bold;
585
+ }
586
+
587
+ /* Color Picker */
588
+ .color-picker-group {
589
+ display: flex;
590
+ gap: 0.5rem;
591
+ margin-top: 0.5rem;
592
+ }
593
+
594
+ .color-option {
595
+ width: 30px;
596
+ height: 30px;
597
+ border-radius: 50%;
598
+ cursor: pointer;
599
+ border: 3px solid transparent;
600
+ transition: all 0.3s ease;
601
+ }
602
+
603
+ .color-option:hover {
604
+ transform: scale(1.1);
605
+ }
606
+
607
+ .color-option.selected {
608
+ border-color: var(--dark);
609
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
610
+ }
611
+ </style>
612
+ </head>
613
+ <body>
614
+ <div class="bg-animation"></div>
615
+
616
+ <header>
617
+ <div class="header-content">
618
+ <div class="logo">
619
+ <i class="fas fa-eye"></i>
620
+ <span>MediaPipe Live Preview</span>
621
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="brand-link">
622
+ Built with anycoder
623
+ </a>
624
+ </div>
625
+ <div class="stats-bar">
626
+ <div class="stat-item">
627
+ <span class="stat-value" id="fpsValue">0</span>
628
+ <span class="stat-label">FPS</span>
629
+ </div>
630
+ <div class="stat-item">
631
+ <span class="stat-value" id="detectionCount">0</span>
632
+ <span class="stat-label">Detections</span>
633
+ </div>
634
+ <div class="stat-item">
635
+ <span class="stat-value" id="activeFeatures">0</span>
636
+ <span class="stat-label">Active</span>
637
+ </div>
638
+ </div>
639
+ </div>
640
+ </header>
641
+
642
+ <main class="container">
643
+ <div class="main-grid">
644
+ <!-- Left Panel - Features -->
645
+ <aside class="control-panel">
646
+ <h2 class="panel-title">
647
+ <i class="fas fa-sliders-h"></i>
648
+ Detection Features
649
+ </h2>
650
+
651
+ <div class="feature-toggle" data-feature="faceMesh">
652
+ <span>
653
+ <i class="fas fa-user"></i> Face Mesh
654
+ </span>
655
+ <div class="toggle-switch"></div>
656
+ </div>
657
+
658
+ <div class="feature-toggle" data-feature="hands">
659
+ <span>
660
+ <i class="fas fa-hand-paper"></i> Hands
661
+ </span>
662
+ <div class="toggle-switch"></div>
663
+ </div>
664
+
665
+ <div class="feature-toggle" data-feature="pose">
666
+ <span>
667
+ <i class="fas fa-running"></i> Pose
668
+ </span>
669
+ <div class="toggle-switch"></div>
670
+ </div>
671
+
672
+ <div class="feature-toggle" data-feature="faceDetection">
673
+ <span>
674
+ <i class="fas fa-user-circle"></i> Face Detection
675
+ </span>
676
+ <div class="toggle-switch"></div>
677
+ </div>
678
+
679
+ <div class="info-card">
680
+ <h4>Pro Tip</h4>
681
+ <p>Enable multiple features simultaneously for comprehensive tracking. Each feature uses different models optimized for specific tasks.</p>
682
+ </div>
683
+ </aside>
684
+
685
+ <!-- Center - Video Preview -->
686
+ <section class="video-container">
687
+ <div class="video-wrapper">
688
+ <video id="inputVideo" autoplay muted playsinline></video>
689
+ <canvas id="outputCanvas"></canvas>
690
+ <div class="loading-overlay" id="loadingOverlay">
691
+ <div class="spinner"></div>
692
+ <div class="loading-text">Initializing Camera...</div>
693
+ </div>
694
+ <div class="performance-monitor">
695
+ <div>Performance: <span class="fps-counter" id="fpsMonitor">0 FPS</span></div>
696
+ </div>
697
+ </div>
698
+
699
+ <div class="video-controls">
700
+ <button class="control-btn btn-primary" id="startBtn">
701
+ <i class="fas fa-play"></i> Start Camera
702
+ </button>
703
+ <button class="control-btn btn-danger" id="stopBtn" disabled>
704
+ <i class="fas fa-stop"></i> Stop
705
+ </button>
706
+ <button class="control-btn btn-secondary" id="screenshotBtn" disabled>
707
+ <i class="fas fa-camera"></i> Screenshot
708
+ </button>
709
+ <button class="control-btn btn-accent" id="recordBtn" disabled>
710
+ <i class="fas fa-video"></i> Record
711
+ </button>
712
+ </div>
713
+ </section>
714
+
715
+ <!-- Right Panel - Settings -->
716
+ <aside class="control-panel">
717
+ <h2 class="panel-title">
718
+ <i class="fas fa-cog"></i>
719
+ Settings
720
+ </h2>
721
+
722
+ <div class="setting-item">
723
+ <label class="setting-label">
724
+ Detection Confidence
725
+ <span class="slider-value" id="confidenceValue">0.5</span>
726
+ </label>
727
+ <input type="range" class="slider" id="confidenceSlider" min="0" max="1" step="0.1" value="0.5">
728
+ </div>
729
+
730
+ <div class="setting-item">
731
+ <label class="setting-label">
732
+ Max Faces
733
+ <span class="slider-value" id="maxFacesValue">1</span>
734
+ </label>
735
+ <input type="range" class="slider" id="maxFacesSlider" min="1" max="5" step="1" value="1">
736
+ </div>
737
+
738
+ <div class="setting-item">
739
+ <label class="setting-label">
740
+ Max Hands
741
+ <span class="slider-value" id="maxHandsValue">2</span>
742
+ </label>
743
+ <input type="range" class="slider" id="maxHandsSlider" min="1" max="4" step="1" value="2">
744
+ </div>
745
+
746
+ <div class="setting-item">
747
+ <label class="setting-label">Landmark Color</label>
748
+ <div class="color-picker-group">
749
+ <div class="color-option selected" style="background: #00FF00" data-color="#00FF00"></div>
750
+ <div class="color-option" style="background: #FF0000" data-color="#FF0000"></div>
751
+ <div class="color-option" style="background: #00FFFF" data-color="#00FFFF"></div>
752
+ <div class="color-option" style="background: #FFFF00" data-color="#FFFF00"></div>
753
+ <div class="color-option" style="background: #FF00FF" data-color="#FF00FF"></div>
754
+ <div class="color-option" style="background: #FFFFFF" data-color="#FFFFFF"></div>
755
+ </div>
756
+ </div>
757
+
758
+ <div class="info-card">
759
+ <h4>Performance</h4>
760
+ <p>Adjust confidence threshold to balance accuracy and performance. Lower values detect more but may include false positives.</p>
761
+ </div>
762
+ </aside>
763
+ </div>
764
+ </main>
765
+
766
+ <!-- Toast Notification -->
767
+ <div class="toast" id="toast">
768
+ <i class="toast-icon fas fa-check-circle"></i>
769
+ <div class="toast-message" id="toastMessage">Operation successful!</div>
770
+ </div>
771
+
772
+ <script>
773
+ // Global Variables
774
+ let camera = null;
775
+ let isStreaming = false;
776
+ let activeFeatures = new Set();
777
+ let landmarkColor = '#00FF00';
778
+ let frameCount = 0;
779
+ let lastTime = performance.now();
780
+ let fps = 0;
781
+ let detectionCount = 0;
782
+ let isRecording = false;
783
+ let mediaRecorder = null;
784
+ let recordedChunks = [];
785
+
786
+ // MediaPipe Models
787
+ let faceMesh = null;
788
+ let hands = null;
789
+ let pose = null;
790
+ let faceDetection = null;
791
+
792
+ // DOM Elements
793
+ const inputVideo = document.getElementById('inputVideo');
794
+ const outputCanvas = document.getElementById('outputCanvas');
795
+ const canvasCtx = outputCanvas.getContext('2d');
796
+ const loadingOverlay = document.getElementById('loadingOverlay');
797
+ const startBtn = document.getElementById('startBtn');
798
+ const stopBtn = document.getElementById('stopBtn');
799
+ const screenshotBtn = document.getElementById('screenshotBtn');
800
+ const recordBtn = document.getElementById('recordBtn');
801
+
802
+ // Initialize MediaPipe Models
803
+ function initializeMediaPipe() {
804
+ // Face Mesh
805
+ faceMesh = new FaceMesh({
806
+ locateFile: (file) => {
807
+ return `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`;
808
+ }
809
+ });
810
+ faceMesh.setOptions({
811
+ maxNumFaces: parseInt(document.getElementById('maxFacesSlider').value),
812
+ refineLandmarks: true,
813
+ minDetectionConfidence: parseFloat(document.getElementById('confidenceSlider').value),
814
+ minTrackingConfidence: 0.5
815
+ });
816
+
817
+ // Hands
818
+ hands = new Hands({
819
+ locateFile: (file) => {
820
+ return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;
821
+ }
822
+ });
823
+ hands.setOptions({
824
+ maxNumHands: parseInt(document.getElementById('maxHandsSlider').value),
825
+ modelComplexity: 1,
826
+ minDetectionConfidence: parseFloat(document.getElementById('confidenceSlider').value),
827
+ minTrackingConfidence: 0.5
828
+ });
829
+
830
+ // Pose
831
+ pose = new Pose({
832
+ locateFile: (file) => {
833
+ return `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`;
834
+ }
835
+ });
836
+ pose.setOptions({
837
+ modelComplexity: 1,
838
+ smoothLandmarks: true,
839
+ minDetectionConfidence: parseFloat(document.getElementById('confidenceSlider').value),
840
+ minTrackingConfidence: 0.5
841
+ });
842
+
843
+ // Face Detection
844
+ faceDetection = new FaceDetection({
845
+ locateFile: (file) => {
846
+ return `https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/${file}`;
847
+ }
848
+ });
849
+ faceDetection.setOptions({
850
+ model: 'short',
851
+ minDetectionConfidence: parseFloat(document.getElementById('confidenceSlider').value)
852
+ });
853
+ }
854
+
855
+ // Start Camera
856
+ async function startCamera() {
857
+ try {
858
+ loadingOverlay.classList.remove('hidden');
859
+
860
+ if (!camera) {
861
+ camera = new Camera(inputVideo, {
862
+ onFrame: async () => {
863
+ if (isStreaming) {
864
+ await processFrame();
865
+ }
866
+ },
867
+ width: 1280,
868
+ height: 720
869
+ });
870
+ }
871
+
872
+ await camera.start();
873
+ isStreaming = true;
874
+
875
+ startBtn.disabled = true;
876
+ stopBtn.disabled = false;
877
+ screenshotBtn.disabled = false;
878
+ recordBtn.disabled = false;
879
+
880
+ loadingOverlay.classList.add('hidden');
881
+ showToast('Camera started successfully!', 'success');
882
+
883
+ } catch (error) {
884
+ console.error('Error starting camera:', error);
885
+ showToast('Failed to start camera. Please check permissions.', 'error');
886
+ loadingOverlay.classList.add('hidden');
887
+ }
888
+ }
889
+
890
+ // Stop Camera
891
+ function stopCamera() {
892
+ if (camera) {
893
+ camera.stop();
894
+ isStreaming = false;
895
+
896
+ startBtn.disabled = false;
897
+ stopBtn.disabled = true;
898
+ screenshotBtn.disabled = true;
899
+ recordBtn.disabled = true;
900
+
901
+ if (isRecording) {
902
+ stopRecording();
903
+ }
904
+
905
+ // Clear canvas
906
+ canvasCtx.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
907
+
908
+ showToast('Camera stopped', 'info');
909
+ }
910
+ }
911
+
912
+ // Process Frame
913
+ async function processFrame() {
914
+ if (!isStreaming) return;
915
+
916
+ canvasCtx.save();
917
+ canvasCtx.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
918
+
919
+ detectionCount = 0;
920
+
921
+ // Process active features
922
+ if (activeFeatures.has('faceMesh')) {
923
+ await faceMesh.send({image: inputVideo});
924
+ }
925
+ if (activeFeatures.has('hands')) {
926
+ await hands.send({image: inputVideo});
927
+ }
928
+ if (activeFeatures.has('pose')) {
929
+ await pose.send({image: inputVideo});
930
+ }
931
+ if (activeFeatures.has('faceDetection')) {
932
+ await faceDetection.send({image: inputVideo});
933
+ }
934
+
935
+ canvasCtx.restore();
936
+
937
+ // Update FPS
938
+ updateFPS();
939
+ updateStats();
940
+ }
941
+
942
+ // Set up MediaPipe results handlers
943
+ function setupResultHandlers() {
944
+ // Face Mesh Results
945
+ faceMesh.onResults((results) => {
946
+ if (results.multiFaceLandmarks) {
947
+ for (const landmarks of results.multiFaceLandmarks) {
948
+ drawConnectors(canvasCtx, landmarks, FACEMESH_TESSELATION,
949
+ {color: landmarkColor, lineWidth: 1});
950
+ drawConnectors(canvasCtx, landmarks, FACEMESH_RIGHT_EYE,
951
+ {color: landmarkColor, lineWidth: 1});
952
+ drawConnectors(canvasCtx, landmarks, FACEMESH_RIGHT_EYEBROW,
953
+ {color: landmarkColor, lineWidth: 1});
954
+ drawConnectors(canvasCtx, landmarks, FACEMESH_LEFT_EYE,
955
+ {color: landmarkColor, lineWidth: 1});
956
+ drawConnectors(canvasCtx, landmarks, FACEMESH_LEFT_EYEBROW,
957
+ {color: landmarkColor, lineWidth: 1});
958
+ drawConnectors(canvasCtx, landmarks, FACEMESH_FACE_OVAL,
959
+ {color: landmarkColor, lineWidth: 1});
960
+ drawConnectors(canvasCtx, landmarks, FACEMESH_LIPS,
961
+ {color: landmarkColor, lineWidth: 1});
962
+ }
963
+ detectionCount += results.multiFaceLandmarks.length;
964
+ }
965
+ });
966
+
967
+ // Hands Results
968
+ hands.onResults((results) => {
969
+ if (results.multiHandLandmarks) {
970
+ for (const landmarks of results.multiHandLandmarks) {
971
+ drawConnectors(canvasCtx, landmarks, HAND_CONNECTIONS,
972
+ {color: landmarkColor, lineWidth: 3});
973
+ drawLandmarks(canvasCtx, landmarks,
974
+ {color: landmarkColor, lineWidth: 1, radius: 3});
975
+ }
976
+ detectionCount += results.multiHandLandmarks.length;
977
+ }
978
+ });
979
+
980
+ // Pose Results
981
+ pose.onResults((results) => {
982
+ if (results.poseLandmarks) {
983
+ drawConnectors(canvasCtx, results.poseLandmarks, POSE_CONNECTIONS,
984
+ {color: landmarkColor, lineWidth: 3});
985
+ drawLandmarks(canvasCtx, results.poseLandmarks,
986
+ {color: landmarkColor, lineWidth: 1, radius: 3});
987
+ detectionCount++;
988
+ }
989
+ });
990
+
991
+ // Face Detection Results
992
+ faceDetection.onResults((results) => {
993
+ if (results.detections) {
994
+ for (const detection of results.detections) {
995
+ drawRectangle(canvasCtx, detection.boundingBox,
996
+ {color: landmarkColor, lineWidth: 3, fillColor: landmarkColor + '20'});
997
+ }
998
+ detectionCount += results.detections.length;
999
+ }
1000
+ });
1001
+ }
1002
+
1003
+ // Update FPS
1004
+ function updateFPS() {
1005
+ frameCount++;
1006
+ const currentTime = performance.now();
1007
+ const deltaTime = currentTime - lastTime;
1008
+
1009
+ if (deltaTime >= 1000) {
1010
+ fps = Math.round((frameCount * 1000) / deltaTime);
1011
+ document.getElementById('fpsValue').textContent = fps;
1012
+ document.getElementById('fpsMonitor').textContent = fps + ' FPS';
1013
+ frameCount = 0;
1014
+ lastTime = currentTime;
1015
+ }
1016
+ }
1017
+
1018
+ // Update Statistics
1019
+ function updateStats() {
1020
+ document.getElementById('detectionCount').textContent = detectionCount;
1021
+ document.getElementById('activeFeatures').textContent = activeFeatures.size;
1022
+ }
1023
+
1024
+ // Take Screenshot
1025
+ function takeScreenshot() {
1026
+ const link = document.createElement('a');
1027
+ link.download = `mediapipe-screenshot-${Date.now()}.png`;
1028
+ link.href = outputCanvas.toDataURL();
1029
+ link.click();
1030
+ showToast('Screenshot saved!', 'success');
1031
+ }
1032
+
1033
+ // Start Recording
1034
+ function startRecording() {
1035
+ const stream = outputCanvas.captureStream(30);
1036
+ mediaRecorder = new MediaRecorder(stream, {
1037
+ mimeType: 'video/webm'
1038
+ });
1039
+
1040
+ recordedChunks = [];
1041
+
1042
+ mediaRecorder.ondataavailable = (event) => {
1043
+ if (event.data.size > 0) {
1044
+ recordedChunks.push(event.data);
1045
+ }
1046
+ };
1047
+
1048
+ mediaRecorder.onstop = () => {
1049
+ const blob = new Blob(recordedChunks, {
1050
+ type: 'video/webm'
1051
+ });
1052
+ const url = URL.createObjectURL(blob);
1053
+ const link = document.createElement('a');
1054
+ link.href = url;
1055
+ link.download = `mediapipe-recording-${Date.now()}.webm`;
1056
+ link.click();
1057
+ showToast('Recording saved!', 'success');
1058
+ };
1059
+
1060
+ mediaRecorder.start();
1061
+ isRecording = true;
1062
+ recordBtn.innerHTML = '<i class="fas fa-stop"></i> Stop Recording';
1063
+ recordBtn.classList.remove('btn-accent');
1064
+ recordBtn.classList.add('btn-danger');
1065
+ showToast('Recording started', 'info');
1066
+ }
1067
+
1068
+ // Stop Recording
1069
+ function stopRecording() {
1070
+ if (mediaRecorder && mediaRecorder.state !== 'inactive') {
1071
+ mediaRecorder.stop();
1072
+ isRecording = false;
1073
+ recordBtn.innerHTML = '<i class="fas fa-video"></i> Record';
1074
+ recordBtn.classList.remove('btn-danger');
1075
+ recordBtn.classList.add('btn-accent');
1076
+ }
1077
+ }
1078
+
1079
+ // Show Toast Notification
1080
+ function showToast(message, type = 'info') {
1081
+ const toast = document.getElementById('toast');
1082
+ const toastMessage = document.getElementById('toastMessage');
1083
+ const toastIcon = toast.querySelector('.toast-icon');
1084
+
1085
+ toastMessage.textContent = message;
1086
+ toast.className = `toast ${type} show`;
1087
+
1088
+ // Update icon based on type
1089
+ if (type === 'success') {
1090
+ toastIcon.className = 'toast-icon fas fa-check-circle';
1091
+ } else if (type === 'error') {
1092
+ toastIcon.className = 'toast-icon fas fa-exclamation-circle';
1093
+ } else {
1094
+ toastIcon.className = 'toast-icon fas fa-info-circle';
1095
+ }
1096
+
1097
+ setTimeout(() => {
1098
+ toast.classList.remove('show');
1099
+ }, 3000);
1100
+ }
1101
+
1102
+ // Event Listeners
1103
+ startBtn.addEventListener('click', startCamera);
1104
+ stopBtn.addEventListener('click', stopCamera);
1105
+ screenshotBtn.addEventListener('click', takeScreenshot);
1106
+ recordBtn.addEventListener('click', () => {
1107
+ if (isRecording) {
1108
+ stopRecording();
1109
+ } else {
1110
+ startRecording();
1111
+ }
1112
+ });
1113
+
1114
+ // Feature Toggles
1115
+ document.querySelectorAll('.feature-toggle').forEach(toggle => {
1116
+ toggle.addEventListener('click', function() {
1117
+ const feature = this.dataset.feature;
1118
+ const switchElement = this.querySelector('.toggle-switch');
1119
+
1120
+ switchElement.classList.toggle('active');
1121
+ this.classList.toggle('active');
1122
+
1123
+ if (activeFeatures.has(feature)) {
1124
+ activeFeatures.delete(feature);
1125
+ } else {
1126
+ activeFeatures.add(feature);
1127
+ }
1128
+
1129
+ updateStats();
1130
+ showToast(`${feature} ${activeFeatures.has(feature) ? 'enabled' : 'disabled'}`, 'info');
1131
+ });
1132
+ });
1133
+
1134
+ // Settings Controls
1135
+ document.getElementById('confidenceSlider').addEventListener('input', function() {
1136
+ const value = this.value;
1137
+ document.getElementById('confidenceValue').textContent = value;
1138
+
1139
+ if (faceMesh) faceMesh.setOptions({minDetectionConfidence: parseFloat(value)});
1140
+ if (hands) hands.setOptions({minDetectionConfidence: parseFloat(value)});
1141
+ if (pose) pose.setOptions({minDetectionConfidence: parseFloat(value)});
1142
+ if (faceDetection) faceDetection.setOptions({minDetectionConfidence: parseFloat(value)});
1143
+ });
1144
+
1145
+ document.getElementById('maxFacesSlider').addEventListener('input', function() {
1146
+ const value = this.value;
1147
+ document.getElementById('maxFacesValue').textContent = value;
1148
+ if (faceMesh) faceMesh.setOptions({maxNumFaces: parseInt(value)});
1149
+ });
1150
+
1151
+ document.getElementById('maxHandsSlider').addEventListener('input', function() {
1152
+ const value = this.value;
1153
+ document.getElementById('maxHandsValue').textContent = value;
1154
+ if (hands) hands.setOptions({maxNumHands: parseInt(value)});
1155
+ });
1156
+
1157
+ // Color Picker
1158
+ document.querySelectorAll('.color-option').forEach(option => {
1159
+ option.addEventListener('click', function() {
1160
+ document.querySelectorAll('.color-option').forEach(opt => opt.classList.remove('selected'));