kimhyunwoo commited on
Commit
fca022f
·
verified ·
1 Parent(s): cde0e5e

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +516 -19
index.html CHANGED
@@ -1,19 +1,516 @@
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" />
6
+ <title>Animated Hugging Face (Single File)</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <!-- Babel for JSX compilation in browser -->
9
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap');
12
+ body {
13
+ font-family: 'Inter', sans-serif;
14
+ }
15
+ /* Custom Animation Utilities */
16
+ @keyframes float {
17
+ 0%, 100% { transform: translateY(0px); }
18
+ 50% { transform: translateY(-15px); }
19
+ }
20
+ .animate-float {
21
+ animation: float 3s ease-in-out infinite;
22
+ }
23
+ @keyframes breathe {
24
+ 0%, 100% { transform: scale(1); }
25
+ 50% { transform: scale(1.02); }
26
+ }
27
+ .animate-breathe {
28
+ animation: breathe 4s ease-in-out infinite;
29
+ }
30
+
31
+ /* Hand Animations */
32
+ @keyframes hand-idle-left {
33
+ 0%, 100% { transform: translate(0, 0) rotate(0deg); }
34
+ 50% { transform: translate(0, -4px) rotate(-5deg); }
35
+ }
36
+ @keyframes hand-idle-right {
37
+ 0%, 100% { transform: translate(0, 0) rotate(0deg); }
38
+ 50% { transform: translate(0, -4px) rotate(5deg); }
39
+ }
40
+
41
+ .animate-hand-idle-left {
42
+ animation: hand-idle-left 3s ease-in-out infinite;
43
+ transform-origin: 35px 150px;
44
+ }
45
+ .animate-hand-idle-right {
46
+ animation: hand-idle-right 3s ease-in-out infinite;
47
+ animation-delay: 1.5s;
48
+ transform-origin: 165px 150px;
49
+ }
50
+ </style>
51
+ </head>
52
+ <body class="bg-slate-900 text-slate-100 antialiased overflow-hidden">
53
+ <div id="root"></div>
54
+
55
+ <script type="text/babel" data-type="module">
56
+ import React, { useState, useEffect, useRef } from 'https://esm.sh/[email protected]';
57
+ import { createRoot } from 'https://esm.sh/[email protected]/client';
58
+ import { Activity, Eye, Zap, Wind, Github, Heart } from 'https://esm.sh/[email protected]';
59
+
60
+ // --- Types (Simulated as Constants for JS) ---
61
+ const Mood = {
62
+ HAPPY: 'HAPPY',
63
+ EXCITED: 'EXCITED',
64
+ SLEEPY: 'SLEEPY',
65
+ SURPRISED: 'SURPRISED'
66
+ };
67
+
68
+ // --- Components ---
69
+
70
+ // 1. HuggingFaceLogo Component
71
+ const HuggingFaceLogo = ({ mood, config, isClicking }) => {
72
+ // Store raw cursor position relative to center of SVG
73
+ const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
74
+ const [blinkOpen, setBlinkOpen] = useState(true);
75
+ const svgRef = useRef(null);
76
+
77
+ // Unified Mouse/Touch tracking
78
+ useEffect(() => {
79
+ const updateCursorPosition = (clientX, clientY) => {
80
+ if (!svgRef.current) return;
81
+
82
+ const rect = svgRef.current.getBoundingClientRect();
83
+ const centerX = rect.left + rect.width / 2;
84
+ const centerY = rect.top + rect.height / 2;
85
+
86
+ setCursorPos({
87
+ x: clientX - centerX,
88
+ y: clientY - centerY
89
+ });
90
+ };
91
+
92
+ const handleMouseMove = (e) => updateCursorPosition(e.clientX, e.clientY);
93
+ const handleTouchMove = (e) => {
94
+ if (e.touches.length > 0) {
95
+ updateCursorPosition(e.touches[0].clientX, e.touches[0].clientY);
96
+ }
97
+ };
98
+
99
+ window.addEventListener('mousemove', handleMouseMove);
100
+ window.addEventListener('touchmove', handleTouchMove);
101
+
102
+ return () => {
103
+ window.removeEventListener('mousemove', handleMouseMove);
104
+ window.removeEventListener('touchmove', handleTouchMove);
105
+ };
106
+ }, []);
107
+
108
+ // Blinking logic
109
+ useEffect(() => {
110
+ if (!config.blink || mood === Mood.SLEEPY) return;
111
+
112
+ const blinkInterval = setInterval(() => {
113
+ setBlinkOpen(false);
114
+ setTimeout(() => setBlinkOpen(true), 150);
115
+ }, 4000 + Math.random() * 2000);
116
+
117
+ return () => clearInterval(blinkInterval);
118
+ }, [config.blink, mood]);
119
+
120
+ // CSS transforms based on state
121
+ const containerClasses = [
122
+ 'w-64 h-64 md:w-96 md:h-96 transition-transform duration-300 ease-out cursor-pointer',
123
+ config.floating ? 'animate-float' : '',
124
+ config.breathing ? 'animate-breathe' : '',
125
+ isClicking ? 'scale-95' : 'hover:scale-105',
126
+ ].join(' ');
127
+
128
+ // SVG Parts
129
+ const renderMouth = () => {
130
+ switch (mood) {
131
+ case Mood.SURPRISED:
132
+ return <ellipse cx="100" cy="140" rx="12" ry="15" fill="#4B3621" />;
133
+ case Mood.SLEEPY:
134
+ return (
135
+ <path
136
+ d="M 85 145 Q 100 140 115 145"
137
+ stroke="#4B3621"
138
+ strokeWidth="5"
139
+ fill="none"
140
+ strokeLinecap="round"
141
+ opacity="0.8"
142
+ />
143
+ );
144
+ case Mood.EXCITED:
145
+ return (
146
+ <path
147
+ d="M 70 135 Q 100 180 130 135 Z"
148
+ stroke="#4B3621"
149
+ strokeWidth="4"
150
+ fill="#6D4C41"
151
+ strokeLinejoin="round"
152
+ />
153
+ );
154
+ default: // HAPPY
155
+ return (
156
+ <path
157
+ d="M 75 140 Q 100 160 125 140"
158
+ stroke="#4B3621"
159
+ strokeWidth="6"
160
+ fill="none"
161
+ strokeLinecap="round"
162
+ />
163
+ );
164
+ }
165
+ };
166
+
167
+ const renderEyes = () => {
168
+ // 1. Calculate Eye Position (Clamped)
169
+ let pupilX = 0;
170
+ let pupilY = 0;
171
+
172
+ if (config.followMouse) {
173
+ const limit = 14;
174
+ const angle = Math.atan2(cursorPos.y, cursorPos.x);
175
+ const dist = Math.min(Math.sqrt(cursorPos.x * cursorPos.x + cursorPos.y * cursorPos.y) / 8, limit);
176
+ pupilX = Math.cos(angle) * dist;
177
+ pupilY = Math.sin(angle) * dist;
178
+ }
179
+
180
+ if (mood === Mood.SLEEPY) {
181
+ return (
182
+ <g opacity="0.8">
183
+ <path d="M 60 95 Q 75 105 90 95" stroke="#4B3621" strokeWidth="5" fill="none" strokeLinecap="round" />
184
+ <path d="M 110 95 Q 125 105 140 95" stroke="#4B3621" strokeWidth="5" fill="none" strokeLinecap="round" />
185
+ </g>
186
+ );
187
+ }
188
+
189
+ const eyeScaleY = blinkOpen ? 1 : 0.1;
190
+
191
+ return (
192
+ <g className="transition-all duration-100" style={{ transformOrigin: '100px 95px', transform: `scaleY(${eyeScaleY})` }}>
193
+ {/* Left Eye */}
194
+ <g transform={`translate(${pupilX * 0.1}, ${pupilY * 0.1})`}>
195
+ <ellipse cx="75" cy="95" rx="13" ry="15" fill="#4B3621" />
196
+ <circle cx={75 + pupilX} cy={95 + pupilY} r="5" fill="white" opacity="0.9" />
197
+ <circle cx={79 + pupilX} cy={92 + pupilY} r="2" fill="white" opacity="0.6" />
198
+ </g>
199
+
200
+ {/* Right Eye */}
201
+ <g transform={`translate(${pupilX * 0.1}, ${pupilY * 0.1})`}>
202
+ <ellipse cx="125" cy="95" rx="13" ry="15" fill="#4B3621" />
203
+ <circle cx={125 + pupilX} cy={95 + pupilY} r="5" fill="white" opacity="0.9" />
204
+ <circle cx={129 + pupilX} cy={92 + pupilY} r="2" fill="white" opacity="0.6" />
205
+ </g>
206
+ </g>
207
+ );
208
+ };
209
+
210
+ const renderHands = () => {
211
+ // Hand Geometry
212
+ const handPath = "M 0 25 Q 0 10 15 5 Q 30 0 45 10 Q 55 20 50 35 L 45 50 Q 35 60 15 55 Q 5 50 0 25 Z";
213
+
214
+ // Dynamic Hand Movement Logic
215
+ const reachLimit = 60; // Max pixels hands can travel from base
216
+ const reachFactor = 0.4; // Sensitivity
217
+
218
+ const targetX = Math.max(Math.min(cursorPos.x * reachFactor, reachLimit), -reachLimit);
219
+ const targetY = Math.max(Math.min(cursorPos.y * reachFactor, reachLimit), -reachLimit);
220
+
221
+ const baseHugX = 25;
222
+ const baseHugY = -25;
223
+
224
+ const leftX = isClicking ? baseHugX + targetX : 0;
225
+ const leftY = isClicking ? baseHugY + targetY : 0;
226
+
227
+ const rightX = isClicking ? -baseHugX + targetX : 0;
228
+ const rightY = isClicking ? baseHugY + targetY : 0;
229
+
230
+ const rotBase = 15;
231
+ const rotDynamic = targetY * 0.3;
232
+
233
+ const leftRot = isClicking ? -rotBase + rotDynamic : 0;
234
+ const rightRot = isClicking ? rotBase - rotDynamic : 0;
235
+
236
+ return (
237
+ <g>
238
+ {/* Left Hand Container */}
239
+ <g className="animate-hand-idle-left" style={{ transformOrigin: '35px 150px' }}>
240
+ <g
241
+ style={{
242
+ transform: `translate(${leftX}px, ${leftY}px) rotate(${leftRot}deg)`,
243
+ transition: 'transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275)'
244
+ }}
245
+ >
246
+ <g transform="translate(10, 135) rotate(-15)">
247
+ <path d={handPath} fill="black" opacity="0.1" transform="translate(4, 4)" />
248
+ <path d={handPath} fill="url(#handGradient)" stroke="#D4A000" strokeWidth="2.5" />
249
+ <ellipse cx="25" cy="25" rx="12" ry="15" fill="white" opacity="0.2" transform="rotate(-10)" />
250
+ </g>
251
+ </g>
252
+ </g>
253
+
254
+ {/* Right Hand Container */}
255
+ <g className="animate-hand-idle-right" style={{ transformOrigin: '165px 150px' }}>
256
+ <g
257
+ style={{
258
+ transform: `translate(${rightX}px, ${rightY}px) rotate(${rightRot}deg)`,
259
+ transition: 'transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275)'
260
+ }}
261
+ >
262
+ <g transform="translate(190, 135) rotate(15) scale(-1, 1)">
263
+ <path d={handPath} fill="black" opacity="0.1" transform="translate(4, 4)" />
264
+ <path d={handPath} fill="url(#handGradient)" stroke="#D4A000" strokeWidth="2.5" />
265
+ <ellipse cx="25" cy="25" rx="12" ry="15" fill="white" opacity="0.2" transform="rotate(-10)" />
266
+ </g>
267
+ </g>
268
+ </g>
269
+ </g>
270
+ );
271
+ };
272
+
273
+ return (
274
+ <div className={containerClasses}>
275
+ <svg
276
+ ref={svgRef}
277
+ viewBox="0 0 200 200"
278
+ className="w-full h-full drop-shadow-2xl"
279
+ style={{ filter: 'drop-shadow(0px 25px 30px rgba(0,0,0,0.3))' }}
280
+ >
281
+ <defs>
282
+ <radialGradient id="faceGradient" cx="40%" cy="30%" r="90%" fx="30%" fy="30%">
283
+ <stop offset="0%" stopColor="#FFEA60" />
284
+ <stop offset="60%" stopColor="#FFD23F" />
285
+ <stop offset="100%" stopColor="#F5C22B" />
286
+ </radialGradient>
287
+
288
+ <radialGradient id="handGradient" cx="30%" cy="30%" r="80%">
289
+ <stop offset="0%" stopColor="#FFEA60" />
290
+ <stop offset="100%" stopColor="#FFC800" />
291
+ </radialGradient>
292
+
293
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
294
+ <feGaussianBlur in="SourceAlpha" stdDeviation="3" />
295
+ <feOffset dx="0" dy="2" result="offsetblur" />
296
+ <feComponentTransfer>
297
+ <feFuncA type="linear" slope="0.3" />
298
+ </feComponentTransfer>
299
+ <feMerge>
300
+ <feMergeNode />
301
+ <feMergeNode in="SourceGraphic" />
302
+ </feMerge>
303
+ </filter>
304
+ </defs>
305
+
306
+ {/* Face Shape */}
307
+ <circle cx="100" cy="100" r="90" fill="url(#faceGradient)" stroke="#D4A000" strokeWidth="3" />
308
+
309
+ {/* Snout */}
310
+ <ellipse cx="100" cy="125" rx="35" ry="25" fill="#FFFFFF" opacity="0.15" />
311
+
312
+ {/* Highlights */}
313
+ <path d="M 50 40 Q 80 20 110 40" stroke="white" strokeWidth="8" strokeLinecap="round" opacity="0.1" fill="none" transform="rotate(-15 80 30)" />
314
+ <circle cx="140" cy="60" r="8" fill="white" opacity="0.15" />
315
+
316
+ {/* Cheeks */}
317
+ <g>
318
+ <ellipse cx="45" cy="115" rx="14" ry="9" fill="#FF5E5E" opacity="0.5" filter="url(#softGlow)" />
319
+ <ellipse cx="155" cy="115" rx="14" ry="9" fill="#FF5E5E" opacity="0.5" filter="url(#softGlow)" />
320
+ <circle cx="48" cy="112" r="2" fill="white" opacity="0.4" />
321
+ <circle cx="158" cy="112" r="2" fill="white" opacity="0.4" />
322
+ </g>
323
+
324
+ {renderEyes()}
325
+ {renderMouth()}
326
+ {renderHands()}
327
+
328
+ </svg>
329
+ </div>
330
+ );
331
+ };
332
+
333
+ // 2. Controls Component
334
+ const Controls = ({ mood, setMood, config, setConfig }) => {
335
+ const toggleConfig = (key) => {
336
+ setConfig(prev => ({ ...prev, [key]: !prev[key] }));
337
+ };
338
+
339
+ return (
340
+ <div className="bg-slate-800/80 backdrop-blur-md p-6 rounded-3xl border border-slate-700 shadow-xl w-full max-w-sm space-y-6">
341
+
342
+ {/* Mood Selector */}
343
+ <div className="space-y-3">
344
+ <label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Character Mood</label>
345
+ <div className="grid grid-cols-2 gap-2">
346
+ {Object.values(Mood).map((m) => (
347
+ <button
348
+ key={m}
349
+ onClick={() => setMood(m)}
350
+ className={`px-4 py-2 rounded-xl text-sm font-semibold transition-all duration-200 ${
351
+ mood === m
352
+ ? 'bg-yellow-500 text-slate-900 shadow-lg scale-105'
353
+ : 'bg-slate-700 text-slate-300 hover:bg-slate-600'
354
+ }`}
355
+ >
356
+ {m.charAt(0) + m.slice(1).toLowerCase()}
357
+ </button>
358
+ ))}
359
+ </div>
360
+ </div>
361
+
362
+ <div className="h-px bg-slate-700 w-full" />
363
+
364
+ {/* Animation Toggles */}
365
+ <div className="space-y-3">
366
+ <label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Behaviors</label>
367
+ <div className="space-y-2">
368
+
369
+ <button
370
+ onClick={() => toggleConfig('followMouse')}
371
+ className={`w-full flex items-center justify-between p-3 rounded-xl transition-all border ${
372
+ config.followMouse ? 'bg-indigo-600/20 border-indigo-500' : 'bg-slate-700/50 border-transparent hover:bg-slate-700'
373
+ }`}
374
+ >
375
+ <div className="flex items-center gap-3">
376
+ <Eye className={`w-5 h-5 ${config.followMouse ? 'text-indigo-400' : 'text-slate-500'}`} />
377
+ <span className="text-sm font-medium">Eye Tracking</span>
378
+ </div>
379
+ <div className={`w-10 h-5 rounded-full relative transition-colors ${config.followMouse ? 'bg-indigo-500' : 'bg-slate-600'}`}>
380
+ <div className={`absolute top-1 w-3 h-3 bg-white rounded-full transition-all ${config.followMouse ? 'left-6' : 'left-1'}`} />
381
+ </div>
382
+ </button>
383
+
384
+ <button
385
+ onClick={() => toggleConfig('floating')}
386
+ className={`w-full flex items-center justify-between p-3 rounded-xl transition-all border ${
387
+ config.floating ? 'bg-blue-600/20 border-blue-500' : 'bg-slate-700/50 border-transparent hover:bg-slate-700'
388
+ }`}
389
+ >
390
+ <div className="flex items-center gap-3">
391
+ <Activity className={`w-5 h-5 ${config.floating ? 'text-blue-400' : 'text-slate-500'}`} />
392
+ <span className="text-sm font-medium">Float Gravity</span>
393
+ </div>
394
+ <div className={`w-10 h-5 rounded-full relative transition-colors ${config.floating ? 'bg-blue-500' : 'bg-slate-600'}`}>
395
+ <div className={`absolute top-1 w-3 h-3 bg-white rounded-full transition-all ${config.floating ? 'left-6' : 'left-1'}`} />
396
+ </div>
397
+ </button>
398
+
399
+ <button
400
+ onClick={() => toggleConfig('breathing')}
401
+ className={`w-full flex items-center justify-between p-3 rounded-xl transition-all border ${
402
+ config.breathing ? 'bg-emerald-600/20 border-emerald-500' : 'bg-slate-700/50 border-transparent hover:bg-slate-700'
403
+ }`}
404
+ >
405
+ <div className="flex items-center gap-3">
406
+ <Wind className={`w-5 h-5 ${config.breathing ? 'text-emerald-400' : 'text-slate-500'}`} />
407
+ <span className="text-sm font-medium">Life Breathing</span>
408
+ </div>
409
+ <div className={`w-10 h-5 rounded-full relative transition-colors ${config.breathing ? 'bg-emerald-500' : 'bg-slate-600'}`}>
410
+ <div className={`absolute top-1 w-3 h-3 bg-white rounded-full transition-all ${config.breathing ? 'left-6' : 'left-1'}`} />
411
+ </div>
412
+ </button>
413
+
414
+ <button
415
+ onClick={() => toggleConfig('blink')}
416
+ className={`w-full flex items-center justify-between p-3 rounded-xl transition-all border ${
417
+ config.blink ? 'bg-amber-600/20 border-amber-500' : 'bg-slate-700/50 border-transparent hover:bg-slate-700'
418
+ }`}
419
+ >
420
+ <div className="flex items-center gap-3">
421
+ <Zap className={`w-5 h-5 ${config.blink ? 'text-amber-400' : 'text-slate-500'}`} />
422
+ <span className="text-sm font-medium">Auto Blink</span>
423
+ </div>
424
+ <div className={`w-10 h-5 rounded-full relative transition-colors ${config.blink ? 'bg-amber-500' : 'bg-slate-600'}`}>
425
+ <div className={`absolute top-1 w-3 h-3 bg-white rounded-full transition-all ${config.blink ? 'left-6' : 'left-1'}`} />
426
+ </div>
427
+ </button>
428
+
429
+ </div>
430
+ </div>
431
+ </div>
432
+ );
433
+ };
434
+
435
+ // 3. App Component
436
+ const App = () => {
437
+ const [mood, setMood] = useState(Mood.HAPPY);
438
+ const [config, setConfig] = useState({
439
+ followMouse: true,
440
+ floating: true,
441
+ breathing: true,
442
+ blink: true
443
+ });
444
+ const [isClicking, setIsClicking] = useState(false);
445
+
446
+ const handleMouseDown = () => setIsClicking(true);
447
+ const handleMouseUp = () => setIsClicking(false);
448
+
449
+ return (
450
+ <div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-indigo-950 flex flex-col items-center justify-center p-4 relative overflow-hidden">
451
+
452
+ {/* Background decoration */}
453
+ <div className="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none opacity-20">
454
+ <div className="absolute top-20 left-20 w-72 h-72 bg-yellow-500 rounded-full blur-[100px]" />
455
+ <div className="absolute bottom-20 right-20 w-96 h-96 bg-indigo-500 rounded-full blur-[120px]" />
456
+ </div>
457
+
458
+ <header className="absolute top-6 left-6 z-10 flex items-center gap-3">
459
+ <h1 className="text-2xl font-bold text-white tracking-tight flex items-center gap-2">
460
+ Hugging Face <span className="text-yellow-400">Alive</span>
461
+ </h1>
462
+ </header>
463
+
464
+ <main className="flex flex-col lg:flex-row items-center justify-center gap-12 z-10 w-full max-w-6xl">
465
+
466
+ {/* Character Stage */}
467
+ <div
468
+ className="relative group cursor-pointer"
469
+ onMouseDown={handleMouseDown}
470
+ onMouseUp={handleMouseUp}
471
+ onTouchStart={handleMouseDown}
472
+ onTouchEnd={handleMouseUp}
473
+ >
474
+ <div className="absolute inset-0 bg-yellow-400/10 rounded-full blur-3xl opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
475
+ <HuggingFaceLogo
476
+ mood={mood}
477
+ config={config}
478
+ isClicking={isClicking}
479
+ />
480
+
481
+ {/* Instruction hint */}
482
+ <div className="absolute -bottom-12 left-1/2 -translate-x-1/2 text-slate-400 text-sm font-medium opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
483
+ Click to hug!
484
+ </div>
485
+ </div>
486
+
487
+ {/* Controls Panel */}
488
+ <div className="w-full max-w-sm">
489
+ <Controls
490
+ mood={mood}
491
+ setMood={setMood}
492
+ config={config}
493
+ setConfig={setConfig}
494
+ />
495
+ </div>
496
+ </main>
497
+
498
+ <footer className="absolute bottom-6 text-slate-500 text-xs flex items-center gap-4">
499
+ <span className="flex items-center gap-1">
500
+ Made with <Heart className="w-3 h-3 text-red-500 fill-current" /> by a React Engineer
501
+ </span>
502
+ <a href="#" className="hover:text-white transition-colors flex items-center gap-1">
503
+ <Github className="w-3 h-3" /> View Source
504
+ </a>
505
+ </footer>
506
+
507
+ </div>
508
+ );
509
+ };
510
+
511
+ // --- Mount ---
512
+ const root = createRoot(document.getElementById('root'));
513
+ root.render(<App />);
514
+ </script>
515
+ </body>
516
+ </html>