ParthSadaria commited on
Commit
6fa9a95
·
verified ·
1 Parent(s): 4a303cf

Update image-playground.html

Browse files
Files changed (1) hide show
  1. image-playground.html +613 -759
image-playground.html CHANGED
@@ -1,769 +1,623 @@
1
  <!DOCTYPE html>
2
- <html lang="en" class="light">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>LOKI.AI IMAGE PLAYGROUND</title>
7
- <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,500;0,700;1,400&display=swap" rel="stylesheet">
8
- <style>
9
- * {
10
- font-family: 'DM Sans', sans-serif;
11
- margin: 0;
12
- padding: 0;
13
- box-sizing: border-box;
14
- }
15
-
16
- body {
17
- background-color: #f9f5f6; /* Light background */
18
- color: #2d3748; /* Dark text */
19
- transition: background-color 0.5s ease, color 0.5s ease;
20
- padding: 20px;
21
- display: flex;
22
- justify-content: center;
23
- align-items: center;
24
- min-height: 100vh;
25
- }
26
-
27
- .dark-mode {
28
- background-color: #1a202c; /* Dark background */
29
- color: #f7fafc; /* Light text */
30
- }
31
-
32
- .container {
33
- max-width: 800px;
34
- width: 100%;
35
- background-color: #fff; /* White container */
36
- border-radius: 12px;
37
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
38
- padding: 30px;
39
- transition: background-color 0.5s ease, box-shadow 0.3s ease;
40
- }
41
-
42
- .dark-mode .container {
43
- background-color: #2d3748; /* Dark container */
44
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
45
- }
46
-
47
- h1 {
48
- font-size: 2.25rem; /* Larger heading */
49
- font-weight: bold;
50
- margin-bottom: 20px;
51
- color: #1e293b; /* Very dark heading */
52
- text-align: center;
53
- transition: color 0.5s ease;
54
- }
55
-
56
- .dark-mode h1 {
57
- color: #f56565; /* Red color for heading in dark mode */
58
- }
59
-
60
- .flex {
61
- display: flex;
62
- align-items: center;
63
- }
64
-
65
- .justify-between {
66
- justify-content: space-between;
67
- }
68
-
69
- .mb-6 {
70
- margin-bottom: 24px;
71
- }
72
-
73
- .items-center {
74
- align-items: center;
75
- }
76
-
77
- .space-x-4 > * + * {
78
- margin-left: 16px;
79
- }
80
-
81
- .text-sm {
82
- font-size: 0.875rem;
83
- }
84
-
85
- .text-gray-500 {
86
- color: #718096;
87
- }
88
-
89
- .dark-mode .text-gray-500 {
90
- color: #a0aec0;
91
- }
92
-
93
- .theme-toggle {
94
- position: relative;
95
- width: 50px; /* Slightly wider */
96
- height: 26px; /* Slightly taller */
97
- border-radius: 13px; /* Ensure proper rounding */
98
- background-color: #e2e8f0; /* Light background */
99
- cursor: pointer;
100
- transition: background-color 0.3s ease;
101
- }
102
-
103
- .dark-mode .theme-toggle {
104
- background-color: #4a5568; /* Darker background */
105
- }
106
-
107
- .theme-toggle-thumb {
108
- position: absolute;
109
- top: 3px; /* Adjusted position */
110
- left: 3px; /* Adjusted position */
111
- width: 20px;
112
- height: 20px;
113
- border-radius: 50%;
114
- background-color: white;
115
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
116
- transition: transform 0.3s ease;
117
- }
118
-
119
- .dark-mode .theme-toggle-thumb {
120
- transform: translateX(24px); /* Increased translation */
121
- }
122
-
123
- .grid {
124
- display: grid;
125
- }
126
-
127
- .grid-cols-1 {
128
- grid-template-columns: repeat(1, minmax(0, 1fr));
129
- }
130
-
131
- .md\:grid-cols-2 {
132
- grid-template-columns: repeat(2, minmax(0, 1fr));
133
- }
134
-
135
- .md\:grid-cols-3 {
136
- grid-template-columns: repeat(3, minmax(0, 1fr));
137
- }
138
-
139
- .gap-4 {
140
- gap: 16px;
141
- }
142
-
143
- .mt-2 {
144
- margin-top: 8px;
145
- }
146
-
147
- .mb-1 {
148
- margin-bottom: 4px;
149
- }
150
-
151
- .block {
152
- display: block;
153
- }
154
-
155
- .text-sm {
156
- font-size: 0.875rem;
157
- }
158
-
159
- .font-medium {
160
- font-weight: 500;
161
- }
162
-
163
- .text-gray-700 {
164
- color: #4a5568;
165
- }
166
-
167
- .dark-mode .text-gray-700 {
168
- color: #cbd5e0;
169
- }
170
-
171
- .relative {
172
- position: relative;
173
- }
174
-
175
- .w-full {
176
- width: 100%;
177
- }
178
-
179
- .px-3 {
180
- padding-left: 12px;
181
- padding-right: 12px;
182
- }
183
-
184
- .py-2 {
185
- padding-top: 8px;
186
- padding-bottom: 8px;
187
- }
188
-
189
- .bg-gray-50 {
190
- background-color: #f7fafc;
191
- }
192
-
193
- .dark-mode .bg-gray-50 {
194
- background-color: #2d3748;
195
- }
196
-
197
- .border {
198
- border-width: 1px;
199
- border-style: solid;
200
- }
201
-
202
- .border-gray-200 {
203
- border-color: #e2e8f0;
204
- }
205
-
206
- .dark-mode .border-gray-200 {
207
- border-color: #4a5568;
208
- }
209
-
210
- .rounded-lg {
211
- border-radius: 8px;
212
- }
213
-
214
- .focus\:outline-none:focus {
215
- outline: none;
216
- }
217
-
218
- .focus\:ring-1:focus {
219
- --tw-ring-offset-width: 0px;
220
- --tw-ring-opacity: 1;
221
- ring-width: 1px;
222
- ring-color: rgba(0, 0, 0, 0.05);
223
- }
224
-
225
- .dark-mode .focus\:ring-1:focus {
226
- ring-color: rgba(255, 255, 255, 0.2);
227
- }
228
-
229
-
230
- .text-gray-900 {
231
- color: #1a202c;
232
- }
233
-
234
- .dark-mode .text-gray-900 {
235
- color: #f7fafc;
236
- }
237
-
238
- .appearance-none {
239
- -webkit-appearance: none;
240
- -moz-appearance: none;
241
- appearance: none;
242
- }
243
-
244
- .pointer-events-none {
245
- pointer-events: none;
246
- }
247
-
248
- .absolute {
249
- position: absolute;
250
- }
251
-
252
- .inset-y-0 {
253
- top: 0;
254
- bottom: 0;
255
- }
256
-
257
- .right-0 {
258
- right: 0;
259
- }
260
-
261
- .flex {
262
- display: flex;
263
- align-items: center;
264
- }
265
-
266
- .px-2 {
267
- padding-left: 8px;
268
- padding-right: 8px;
269
- }
270
-
271
- .text-gray-300 {
272
- color: #cbd5e0;
273
- }
274
-
275
- .dark-mode .text-gray-300 {
276
- color: #a0aec0;
277
- }
278
-
279
- .h-4 {
280
- height: 1rem;
281
- }
282
-
283
- .w-4 {
284
- width: 1rem;
285
- }
286
-
287
- .fill-none {
288
- fill: none;
289
- }
290
-
291
- .stroke-current {
292
- stroke: currentColor;
293
- }
294
-
295
- .stroke-linecap-round {
296
- stroke-linecap: round;
297
- }
298
-
299
- .stroke-linejoin-round {
300
- stroke-linejoin: round;
301
- }
302
-
303
- .stroke-width-2 {
304
- stroke-width: 2;
305
- }
306
-
307
- .mt-6 {
308
- margin-top: 24px;
309
- }
310
-
311
- .text-center {
312
- text-align: center;
313
- }
314
-
315
- .text-lg {
316
- font-size: 1.125rem;
317
- line-height: 1.75rem;
318
- }
319
-
320
- .font-semibold {
321
- font-weight: 600;
322
- }
323
-
324
- .hidden {
325
- display: none;
326
- }
327
-
328
- .loading {
329
- width: 40px;
330
- height: 40px;
331
- border: 4px solid #f3f3f3;
332
- border-bottom-color: #000;
333
- border-radius: 50%;
334
- animation: rotation 1.2s linear infinite;
335
- }
336
-
337
- .dark-mode .loading {
338
- border-color: #333;
339
- border-bottom-color: #fff;
340
- }
341
-
342
- @keyframes rotation {
343
- 0% { transform: rotate(0deg); }
344
- 100% { transform: rotate(360deg); }
345
- }
346
-
347
- .image-container {
348
- border-radius: 8px;
349
- overflow: hidden;
350
- position: relative; /* Make sure the container is a positioning context */
351
- }
352
-
353
- .image-container img {
354
- width: 100%;
355
- height: auto;
356
- display: block; /* Prevent extra space below image */
357
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* Add shadow to images */
358
- transition: transform 0.2s ease-in-out;
359
- }
360
-
361
- .image-container img:hover {
362
- transform: scale(1.03);
363
- }
364
-
365
- .btn-primary {
366
- padding: 10px 20px;
367
- border-radius: 8px;
368
- font-weight: 500;
369
- cursor: pointer;
370
- transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
371
- border: none;
372
- display: inline-flex;
373
- align-items: center;
374
- justify-content: center;
375
- gap: 8px;
376
- }
377
-
378
- .btn-primary {
379
- background-color: #6b7280; /* Gray 600 */
380
- color: white;
381
- }
382
-
383
- .btn-primary:hover {
384
- background-color: #4b5563; /* Gray 700 */
385
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
386
- }
387
-
388
- .dark-mode .btn-primary {
389
- background-color: #f5f5f5;
390
- color: #1a202c;
391
- }
392
-
393
- .dark-mode .btn-primary:hover {
394
- background-color: #e0e0e0;
395
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
396
- }
397
-
398
- .btn-secondary {
399
- padding: 8px;
400
- border-radius: 50%;
401
- cursor: pointer;
402
- transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
403
- border: none;
404
- display: flex; /* Use flexbox for centering */
405
- align-items: center;
406
- justify-content: center;
407
- }
408
-
409
- .btn-secondary {
410
- background-color: white;
411
- color: #1a202c;
412
- }
413
-
414
- .btn-secondary:hover {
415
- background-color: #f0f0f0;
416
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
417
- }
418
-
419
- .dark-mode .btn-secondary {
420
- background-color: #4a5568;
421
- color: #fff;
422
- }
423
-
424
- .dark-mode .btn-secondary:hover {
425
- background-color: #718096;
426
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
427
- }
428
-
429
- #error {
430
- background-color: #fee2e2;
431
- color: #dc2626;
432
- padding: 16px;
433
- border-radius: 8px;
434
- margin-top: 20px;
435
- border: 1px solid #fecaca;
436
- }
437
-
438
- .dark-mode #error {
439
- background-color: #721c24;
440
- color: #fecaca;
441
- border-color: #b91c1c;
442
- }
443
-
444
- .text-xs {
445
- font-size: 0.75rem;
446
- color: #a0aec0;
447
- margin-top: 16px;
448
- text-align: center;
449
- }
450
-
451
- .dark-mode .text-xs {
452
- color: #cbd5e0;
453
- }
454
-
455
- /* Confetti Animation */
456
- .confetti {
457
- position: fixed;
458
- top: 0;
459
- left: 0;
460
- width: 100%;
461
- height: 100%;
462
- pointer-events: none; /* Allows clicks to go through */
463
- z-index: 1000; /* Ensure it's on top */
464
- }
465
-
466
- .confetti-piece {
467
- position: absolute;
468
- width: 10px;
469
- height: 10px;
470
- background-color: #fcd34d; /* Yellow */
471
- border-radius: 50%;
472
- opacity: 0;
473
- animation: confetti-fall 3s forwards, confetti-rotate 2s infinite;
474
- }
475
-
476
- .confetti-piece:nth-child(even) {
477
- background-color: #60a5fa; /* Blue */
478
- }
479
-
480
- .confetti-piece:nth-child(3n) {
481
- background-color: #f472b6; /* Pink */
482
- }
483
-
484
- .confetti-piece:nth-child(4n) {
485
- background-color: #34d399; /* Green */
486
- }
487
-
488
- @keyframes confetti-fall {
489
- from {
490
- opacity: 0;
491
- transform: translateY(-50px) rotate(0deg);
492
- }
493
- to {
494
- opacity: 1;
495
- transform: translateY(100vh) rotate(720deg);
496
- }
497
- }
498
-
499
- @keyframes confetti-rotate {
500
- from {
501
- transform: rotate(0deg);
502
- }
503
- to {
504
- transform: rotate(360deg);
505
- }
506
- }
507
- </style>
508
  </head>
509
- <body class="light">
510
- <div class="container">
511
- <h1>LOKI.AI IMAGE PLAYGROUND</h1>
512
-
513
- <div class="flex justify-between mb-6">
514
- <div class="flex items-center space-x-4">
515
- <span class="text-sm text-gray-500">Theme</span>
516
- <div id="theme-toggle" class="theme-toggle">
517
- <div class="theme-toggle-thumb"></div>
518
- </div>
519
- </div>
520
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
 
522
- <div class="space-y-4">
523
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
524
- <div>
525
- <label for="model" class="block text-sm font-medium text-gray-700 mb-1">Select Model</label>
526
- <div class="relative">
527
- <select id="model" class="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 text-gray-900 appearance-none">
528
- <option value="Flux Realism">Flux Realism</option>
529
- <option value="Flux Pro Ultra">Flux Pro Ultra</option>
530
- <option value="grok-2-aurora">grok-2-aurora</option>
531
- <option value="Flux Pro">Flux Pro</option>
532
- <option value="Flux Pro Ultra Raw">Flux Pro Ultra Raw</option>
533
- <option value="Flux Dev">Flux Dev</option>
534
- <option value="Flux Schnell">Flux Schnell</option>
535
- <option value="stable-diffusion-3-large-turbo">stable-diffusion-3-large-turbo</option>
536
- <option value="sdxl-lightning-4step">sdxl-lightning-4step</option>
537
- <option value="dall-e-3">dall-e-3</option>
538
- </select>
539
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-300">
540
- <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
541
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
542
- </svg>
543
- </div>
544
- </div>
545
- </div>
546
- <div>
547
- <label for="prompt" class="block text-sm font-medium text-gray-700 mb-1">Enter Prompt</label>
548
- <input type="text" id="prompt" placeholder="Describe what you want to see..." class="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 text-gray-900" value="sky">
549
- </div>
550
- </div>
551
-
552
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-2">
553
- <div>
554
- <label for="image-size" class="block text-sm font-medium text-gray-700 mb-1">Image Size</label>
555
- <select id="image-size" class="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 text-gray-900 appearance-none">
556
- <option value="512">512 x 512</option>
557
- <option value="768">768 x 768</option>
558
- <option value="1024" selected>1024 x 1024</option>
559
- <option value="1536">1536 x 1536</option>
560
- </select>
561
- </div>
562
- <div>
563
- <label for="image-count" class="block text-sm font-medium text-gray-700 mb-1">Number of Images</label>
564
- <select id="image-count" class="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 text-gray-900 appearance-none">
565
- <option value="1" selected>1</option>
566
- <option value="2">2</option>
567
- <option value="4">4</option>
568
- </select>
569
- </div>
570
- <div class="flex items-end">
571
- <button id="generate" class="btn-primary">
572
- Generate Image
573
- </button>
574
- </div>
575
- </div>
576
-
577
- <div id="result" class="mt-6 hidden">
578
- <div class="text-center mb-4">
579
- <h2 class="text-lg font-semibold">Your Creation</h2>
580
- <p class="text-sm text-gray-500">Created with <span id="model-used"></span></p>
581
- </div>
582
- <div id="images-container" class="grid grid-cols-1 md:grid-cols-2 gap-4">
583
- </div>
584
- </div>
585
-
586
- <div id="loading" class="flex flex-col items-center justify-center py-6 hidden">
587
- <div class="loading mb-3"></div>
588
- <p class="text-gray-600 text-sm">Creating your image...</p>
589
- </div>
590
-
591
- <div id="error" class="hidden">
592
- <p class="font-medium">Oops! Something went wrong.</p>
593
- <p class="text-sm">Please try again or check your connection.</p>
594
- </div>
595
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
596
  </div>
597
-
598
- <div class="text-xs">
599
- © 2025 LOKI.AI IMAGE PLAYGROUND | All rights reserved
600
  </div>
601
-
602
- <div id="confetti-canvas" class="confetti"></div>
603
-
604
- <script>
605
- document.addEventListener('DOMContentLoaded', () => {
606
- // Elements
607
- const themeToggle = document.getElementById('theme-toggle');
608
- const generateBtn = document.getElementById('generate');
609
- const promptInput = document.getElementById('prompt');
610
- const modelSelect = document.getElementById('model');
611
- const imageSizeSelect = document.getElementById('image-size');
612
- const imageCountSelect = document.getElementById('image-count');
613
- const resultDiv = document.getElementById('result');
614
- const loadingDiv = document.getElementById('loading');
615
- const errorDiv = document.getElementById('error');
616
- const imagesContainer = document.getElementById('images-container');
617
- const modelUsed = document.getElementById('model-used');
618
- const body = document.body;
619
-
620
- // Theme Toggle
621
- themeToggle.addEventListener('click', () => {
622
- body.classList.toggle('dark-mode');
623
- localStorage.setItem('theme', body.classList.contains('dark-mode') ? 'dark-mode' : 'light');
624
- });
625
-
626
- // Check for saved theme preference
627
- if (localStorage.getItem('theme') === 'dark-mode' ||
628
- (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
629
- body.classList.add('dark-mode');
630
- } else {
631
- body.classList.remove('dark-mode');
632
- }
633
-
634
- // Generate image
635
- generateBtn.addEventListener('click', async () => {
636
- const prompt = promptInput.value.trim();
637
- const model = modelSelect.value;
638
- const size = parseInt(imageSizeSelect.value);
639
- const number = parseInt(imageCountSelect.value);
640
-
641
- if (!prompt) {
642
- promptInput.style.borderColor = 'red';
643
- setTimeout(() => {
644
- promptInput.style.borderColor = '';
645
- }, 1500);
646
- return;
647
- }
648
-
649
- // Show loading state
650
- resultDiv.classList.add('hidden');
651
- errorDiv.classList.add('hidden');
652
- loadingDiv.classList.remove('hidden');
653
- generateBtn.disabled = true;
654
-
655
- try {
656
- const response = await fetch('https://parthsadaria-lokiai.hf.space/images/generations', {
657
- method: 'POST',
658
- headers: {
659
- 'Content-Type': 'application/json',
660
- },
661
- body: JSON.stringify({
662
- model: model,
663
- prompt: prompt,
664
- size: size,
665
- number: number
666
- })
667
- });
668
-
669
- if (!response.ok) {
670
- throw new Error('API request failed');
671
- }
672
-
673
- const data = await response.json();
674
-
675
- // Display result
676
- loadingDiv.classList.add('hidden');
677
- resultDiv.classList.remove('hidden');
678
- modelUsed.textContent = model;
679
-
680
- // Clear previous images
681
- imagesContainer.innerHTML = '';
682
-
683
- // Add generated images
684
- if (data.data && data.data.length > 0) {
685
- // Set grid columns based on number of images.
686
- if (number > 1) {
687
- imagesContainer.className = `grid grid-cols-1 ${number > 1 ? 'md:grid-cols-2' : ''} gap-4`;
688
- } else {
689
- imagesContainer.className = 'mx-auto max-w-lg';
690
- }
691
- data.data.forEach((item, index) => { // Changed to data.data and iterate over item
692
- const imgSrc = item.url;
693
- const imgContainer = document.createElement('div');
694
- imgContainer.className = 'image-container relative';
695
-
696
- const img = document.createElement('img');
697
- img.src = imgSrc;
698
- img.className = 'w-full h-auto';
699
- img.alt = `Generated image ${index + 1}`;
700
-
701
- const downloadBtn = document.createElement('button');
702
- downloadBtn.className = 'btn-secondary absolute bottom-3 right-3';
703
- downloadBtn.innerHTML = `
704
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
705
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
706
- </svg>
707
- `;
708
-
709
- downloadBtn.addEventListener('click', () => {
710
- const a = document.createElement('a');
711
- a.href = imgSrc;
712
- a.download = `loki-ai-${model}-${index + 1}-${new Date().getTime()}.png`;
713
- document.body.appendChild(a);
714
- a.click();
715
- document.body.removeChild(a);
716
- });
717
-
718
- imgContainer.appendChild(img);
719
- imgContainer.appendChild(downloadBtn);
720
- imagesContainer.appendChild(imgContainer);
721
- });
722
- // Trigger confetti animation
723
- triggerConfetti();
724
- }
725
-
726
- } catch (error) {
727
- console.error('Error:', error);
728
- loadingDiv.classList.add('hidden');
729
- errorDiv.classList.remove('hidden');
730
- } finally {
731
- generateBtn.disabled = false;
732
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
  });
734
-
735
- // Enter key to generate
736
- promptInput.addEventListener('keypress', (e) => {
737
- if (e.key === 'Enter') {
738
- generateBtn.click();
739
- }
740
- });
741
-
742
- // Confetti Animation
743
- function triggerConfetti() {
744
- const confettiCanvas = document.getElementById('confetti-canvas');
745
- const numConfetti = 200; // More confetti
746
-
747
- confettiCanvas.innerHTML = ''; // Clear any existing confetti
748
-
749
- for (let i = 0; i < numConfetti; i++) {
750
- const confettiPiece = document.createElement('div');
751
- confettiPiece.className = 'confetti-piece';
752
- confettiPiece.style.left = `${Math.random() * 100}vw`;
753
- confettiPiece.style.animationDuration = `${Math.random() * 2 + 2}s`; // Longer duration
754
- confettiPiece.style.opacity = '0'; // Start with 0 opacity
755
- confettiPiece.style.transform = `scale(${Math.random() * 0.5 + 0.5})`; // Varying size
756
- confettiPiece.style.rotate = `${Math.random() * 360}deg`;
757
-
758
- confettiCanvas.appendChild(confettiPiece);
759
-
760
- // Remove confetti element after animation finishes
761
- confettiPiece.addEventListener('animationend', () => {
762
- confettiPiece.remove();
763
- });
764
- }
765
- }
766
- });
767
- </script>
768
  </body>
769
- </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>LOKI.AI IMAGE PLAYGROUND</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,500;0,700;1,400&display=swap" rel="stylesheet">
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
9
+ <style>
10
+ :root {
11
+ --primary-bg: #ffffff;
12
+ --secondary-bg: #f8f8f8;
13
+ --text-color: #000000;
14
+ --border-color: #e0e0e0;
15
+ --accent-color: #000000;
16
+ --card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
17
+ }
18
+
19
+ .dark {
20
+ --primary-bg: #121212;
21
+ --secondary-bg: #1e1e1e;
22
+ --text-color: #ffffff;
23
+ --border-color: #333333;
24
+ --accent-color: #ffffff;
25
+ --card-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
26
+ }
27
+
28
+ * {
29
+ margin: 0;
30
+ padding: 0;
31
+ box-sizing: border-box;
32
+ font-family: 'DM Sans', sans-serif;
33
+ }
34
+
35
+ body {
36
+ background-color: var(--secondary-bg);
37
+ color: var(--text-color);
38
+ transition: all 0.3s ease;
39
+ padding: 20px;
40
+ }
41
+
42
+ .container {
43
+ max-width: 1000px;
44
+ margin: 0 auto;
45
+ }
46
+
47
+ .card {
48
+ background-color: var(--primary-bg);
49
+ border-radius: 12px;
50
+ padding: 24px;
51
+ box-shadow: var(--card-shadow);
52
+ transition: all 0.3s ease;
53
+ }
54
+
55
+ .header {
56
+ display: flex;
57
+ justify-content: space-between;
58
+ align-items: center;
59
+ margin-bottom: 24px;
60
+ flex-wrap: wrap;
61
+ gap: 12px;
62
+ }
63
+
64
+ .title {
65
+ font-size: 28px;
66
+ font-weight: 700;
67
+ color: var(--text-color);
68
+ }
69
+
70
+ .theme-toggle {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 8px;
74
+ }
75
+
76
+ .toggle-label {
77
+ font-size: 14px;
78
+ color: var(--text-color);
79
+ opacity: 0.7;
80
+ }
81
+
82
+ .toggle-switch {
83
+ position: relative;
84
+ width: 48px;
85
+ height: 24px;
86
+ background-color: #e5e5e5;
87
+ border-radius: 12px;
88
+ cursor: pointer;
89
+ transition: background-color 0.3s;
90
+ }
91
+
92
+ .dark .toggle-switch {
93
+ background-color: #555;
94
+ }
95
+
96
+ .toggle-thumb {
97
+ position: absolute;
98
+ top: 2px;
99
+ left: 2px;
100
+ width: 20px;
101
+ height: 20px;
102
+ border-radius: 50%;
103
+ background-color: white;
104
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
105
+ transition: transform 0.3s;
106
+ }
107
+
108
+ .dark .toggle-thumb {
109
+ transform: translateX(24px);
110
+ }
111
+
112
+ .form-row {
113
+ display: grid;
114
+ grid-template-columns: 1fr;
115
+ gap: 16px;
116
+ margin-bottom: 16px;
117
+ }
118
+
119
+ @media (min-width: 768px) {
120
+ .form-row {
121
+ grid-template-columns: 1fr 1fr;
122
+ }
123
+ .form-row.three-cols {
124
+ grid-template-columns: 1fr 1fr 1fr;
125
+ }
126
+ }
127
+
128
+ .form-group {
129
+ display: flex;
130
+ flex-direction: column;
131
+ gap: 6px;
132
+ }
133
+
134
+ .form-label {
135
+ font-size: 14px;
136
+ font-weight: 500;
137
+ color: var(--text-color);
138
+ opacity: 0.8;
139
+ }
140
+
141
+ .form-control {
142
+ padding: 10px 12px;
143
+ border-radius: 8px;
144
+ border: 1px solid var(--border-color);
145
+ background-color: var(--secondary-bg);
146
+ color: var(--text-color);
147
+ font-size: 14px;
148
+ transition: all 0.2s;
149
+ appearance: none;
150
+ }
151
+
152
+ .form-control:focus {
153
+ outline: none;
154
+ border-color: var(--accent-color);
155
+ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
156
+ }
157
+
158
+ .dark .form-control:focus {
159
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
160
+ }
161
+
162
+ .select-wrapper {
163
+ position: relative;
164
+ }
165
+
166
+ .select-wrapper:after {
167
+ content: '';
168
+ position: absolute;
169
+ top: 50%;
170
+ right: 12px;
171
+ transform: translateY(-50%);
172
+ width: 0;
173
+ height: 0;
174
+ border-left: 5px solid transparent;
175
+ border-right: 5px solid transparent;
176
+ border-top: 5px solid var(--text-color);
177
+ pointer-events: none;
178
+ }
179
+
180
+ .btn {
181
+ padding: 10px 18px;
182
+ border-radius: 8px;
183
+ font-weight: 500;
184
+ cursor: pointer;
185
+ transition: all 0.2s;
186
+ border: none;
187
+ text-align: center;
188
+ }
189
+
190
+ .btn-primary {
191
+ background-color: var(--accent-color);
192
+ color: var(--primary-bg);
193
+ }
194
+
195
+ .btn-primary:hover {
196
+ opacity: 0.9;
197
+ transform: translateY(-2px);
198
+ }
199
+
200
+ .btn-primary:active {
201
+ transform: translateY(0);
202
+ }
203
+
204
+ .btn-download {
205
+ background-color: rgba(255, 255, 255, 0.2);
206
+ backdrop-filter: blur(4px);
207
+ padding: 8px;
208
+ border-radius: 50%;
209
+ position: absolute;
210
+ bottom: 10px;
211
+ right: 10px;
212
+ display: flex;
213
+ align-items: center;
214
+ justify-content: center;
215
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
216
+ }
217
+
218
+ .dark .btn-download {
219
+ background-color: rgba(0, 0, 0, 0.3);
220
+ }
221
+
222
+ .btn-download svg {
223
+ width: 20px;
224
+ height: 20px;
225
+ stroke: var(--accent-color);
226
+ }
227
+
228
+ .btn-full {
229
+ width: 100%;
230
+ }
231
+
232
+ .text-center {
233
+ text-align: center;
234
+ }
235
+
236
+ .result {
237
+ margin-top: 24px;
238
+ display: none;
239
+ }
240
+
241
+ .result-title {
242
+ font-size: 18px;
243
+ font-weight: 500;
244
+ margin-bottom: 4px;
245
+ }
246
+
247
+ .result-subtitle {
248
+ font-size: 14px;
249
+ opacity: 0.7;
250
+ margin-bottom: 16px;
251
+ }
252
+
253
+ .images-grid {
254
+ display: grid;
255
+ grid-template-columns: 1fr;
256
+ gap: 16px;
257
+ }
258
+
259
+ .images-grid.multi-column {
260
+ grid-template-columns: repeat(2, 1fr);
261
+ }
262
+
263
+ .image-wrapper {
264
+ position: relative;
265
+ border-radius: 8px;
266
+ overflow: hidden;
267
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
268
+ transform-origin: center;
269
+ }
270
+
271
+ .dark .image-wrapper {
272
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
273
+ }
274
+
275
+ .image-wrapper img {
276
+ width: 100%;
277
+ height: auto;
278
+ display: block;
279
+ transition: transform 0.3s ease;
280
+ }
281
+
282
+ .image-wrapper:hover img {
283
+ transform: scale(1.03);
284
+ }
285
+
286
+ .loading {
287
+ display: none;
288
+ flex-direction: column;
289
+ align-items: center;
290
+ justify-content: center;
291
+ padding: 32px 0;
292
+ }
293
+
294
+ .loading-spinner {
295
+ width: 40px;
296
+ height: 40px;
297
+ border: 4px solid rgba(0, 0, 0, 0.1);
298
+ border-left-color: var(--accent-color);
299
+ border-radius: 50%;
300
+ animation: spinner 1s linear infinite;
301
+ margin-bottom: 16px;
302
+ }
303
+
304
+ .dark .loading-spinner {
305
+ border-color: rgba(255, 255, 255, 0.1);
306
+ border-left-color: var(--accent-color);
307
+ }
308
+
309
+ @keyframes spinner {
310
+ to {
311
+ transform: rotate(360deg);
312
+ }
313
+ }
314
+
315
+ .loading-text {
316
+ font-size: 14px;
317
+ opacity: 0.7;
318
+ }
319
+
320
+ .error {
321
+ background-color: rgba(255, 0, 0, 0.1);
322
+ color: #e53e3e;
323
+ padding: 16px;
324
+ border-radius: 8px;
325
+ margin-top: 24px;
326
+ display: none;
327
+ }
328
+
329
+ .dark .error {
330
+ background-color: rgba(255, 0, 0, 0.05);
331
+ }
332
+
333
+ .error-title {
334
+ font-size: 16px;
335
+ font-weight: 500;
336
+ margin-bottom: 4px;
337
+ }
338
+
339
+ .error-message {
340
+ font-size: 14px;
341
+ opacity: 0.8;
342
+ }
343
+
344
+ .footer {
345
+ margin-top: 16px;
346
+ text-align: center;
347
+ font-size: 12px;
348
+ opacity: 0.5;
349
+ }
350
+
351
+ .confetti {
352
+ position: fixed;
353
+ width: 10px;
354
+ height: 10px;
355
+ background-color: #f00;
356
+ opacity: 0;
357
+ top: 0;
358
+ left: 0;
359
+ }
360
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  </head>
362
+ <body>
363
+ <div class="container">
364
+ <div class="card animate__animated animate__fadeIn">
365
+ <div class="header">
366
+ <h1 class="title animate__animated animate__slideInLeft">LOKI.AI IMAGE PLAYGROUND</h1>
367
+ <div class="theme-toggle animate__animated animate__slideInRight">
368
+ <span class="toggle-label">Theme</span>
369
+ <div id="theme-toggle" class="toggle-switch">
370
+ <div class="toggle-thumb"></div>
371
+ </div>
 
372
  </div>
373
+ </div>
374
+
375
+ <div class="form-row animate__animated animate__fadeInUp" style="animation-delay: 0.1s;">
376
+ <div class="form-group">
377
+ <label for="model" class="form-label">Select Model</label>
378
+ <div class="select-wrapper">
379
+ <select id="model" class="form-control">
380
+ <option value="Flux Realism">Flux Realism</option>
381
+ <option value="Flux Pro Ultra">Flux Pro Ultra</option>
382
+ <option value="grok-2-aurora">grok-2-aurora</option>
383
+ <option value="Flux Pro">Flux Pro</option>
384
+ <option value="Flux Pro Ultra Raw">Flux Pro Ultra Raw</option>
385
+ <option value="Flux Dev">Flux Dev</option>
386
+ <option value="Flux Schnell">Flux Schnell</option>
387
+ <option value="stable-diffusion-3-large-turbo">stable-diffusion-3-large-turbo</option>
388
+ <option value="sdxl-lightning-4step">sdxl-lightning-4step</option>
389
+ <option value="dall-e-3">dall-e-3</option>
390
+ </select>
391
+ </div>
392
+ </div>
393
+ <div class="form-group">
394
+ <label for="prompt" class="form-label">Enter Prompt</label>
395
+ <input type="text" id="prompt" class="form-control" placeholder="Describe what you want to see..." value="sky">
396
+ </div>
397
+ </div>
398
+
399
+ <div class="form-row three-cols animate__animated animate__fadeInUp" style="animation-delay: 0.2s;">
400
+ <div class="form-group">
401
+ <label for="image-size" class="form-label">Image Size</label>
402
+ <div class="select-wrapper">
403
+ <select id="image-size" class="form-control">
404
+ <option value="512">512 x 512</option>
405
+ <option value="768">768 x 768</option>
406
+ <option value="1024" selected>1024 x 1024</option>
407
+ <option value="1536">1536 x 1536</option>
408
+ </select>
409
+ </div>
410
+ </div>
411
+ <div class="form-group">
412
+ <label for="image-count" class="form-label">Number of Images</label>
413
+ <div class="select-wrapper">
414
+ <select id="image-count" class="form-control">
415
+ <option value="1" selected>1</option>
416
+ <option value="2">2</option>
417
+ <option value="4">4</option>
418
+ </select>
419
+ </div>
420
+ </div>
421
+ <div class="form-group">
422
+ <label class="form-label">&nbsp;</label>
423
+ <button id="generate" class="btn btn-primary btn-full animate__animated animate__pulse animate__infinite">
424
+ Generate Image
425
+ </button>
426
+ </div>
427
+ </div>
428
 
429
+ <div id="result" class="result">
430
+ <div class="text-center animate__animated animate__fadeIn">
431
+ <h2 class="result-title">Your Creation</h2>
432
+ <p class="result-subtitle">Created with <span id="model-used"></span></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  </div>
434
+ <div id="images-container" class="images-grid"></div>
435
+ </div>
436
+
437
+ <div id="loading" class="loading">
438
+ <div class="loading-spinner"></div>
439
+ <p class="loading-text">Creating your masterpiece...</p>
440
+ </div>
441
+
442
+ <div id="error" class="error">
443
+ <h3 class="error-title">Oops! Something went wrong.</h3>
444
+ <p class="error-message">Please try again or check your connection.</p>
445
+ </div>
446
  </div>
447
+
448
+ <div class="footer">
449
+ © 2025 LOKI.AI IMAGE PLAYGROUND | All rights reserved
450
  </div>
451
+ </div>
452
+
453
+ <script>
454
+ document.addEventListener('DOMContentLoaded', () => {
455
+ // Elements
456
+ const themeToggle = document.getElementById('theme-toggle');
457
+ const generateBtn = document.getElementById('generate');
458
+ const promptInput = document.getElementById('prompt');
459
+ const modelSelect = document.getElementById('model');
460
+ const imageSizeSelect = document.getElementById('image-size');
461
+ const imageCountSelect = document.getElementById('image-count');
462
+ const resultDiv = document.getElementById('result');
463
+ const loadingDiv = document.getElementById('loading');
464
+ const errorDiv = document.getElementById('error');
465
+ const imagesContainer = document.getElementById('images-container');
466
+ const modelUsed = document.getElementById('model-used');
467
+
468
+ // Theme Toggle
469
+ themeToggle.addEventListener('click', () => {
470
+ document.body.classList.toggle('dark');
471
+ localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
472
+ });
473
+
474
+ // Check for saved theme preference
475
+ if (localStorage.getItem('theme') === 'dark' ||
476
+ (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
477
+ document.body.classList.add('dark');
478
+ }
479
+
480
+ // Create confetti
481
+ function createConfetti() {
482
+ const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff'];
483
+ const confettiCount = 100;
484
+
485
+ for (let i = 0; i < confettiCount; i++) {
486
+ const confetti = document.createElement('div');
487
+ confetti.className = 'confetti';
488
+ confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
489
+ confetti.style.left = Math.random() * 100 + 'vw';
490
+ confetti.style.opacity = Math.random() + 0.5;
491
+ confetti.style.width = Math.random() * 10 + 5 + 'px';
492
+ confetti.style.height = Math.random() * 10 + 5 + 'px';
493
+ document.body.appendChild(confetti);
494
+
495
+ const animation = confetti.animate([
496
+ { transform: 'translateY(0) rotate(0)', opacity: 1 },
497
+ { transform: `translateY(${window.innerHeight}px) rotate(${Math.random() * 360}deg)`, opacity: 0 }
498
+ ], {
499
+ duration: Math.random() * 2000 + 2000,
500
+ easing: 'cubic-bezier(0, 0.55, 0.45, 1)'
501
+ });
502
+
503
+ animation.onfinish = () => confetti.remove();
504
+ }
505
+ }
506
+
507
+ // Generate image
508
+ generateBtn.addEventListener('click', async () => {
509
+ const prompt = promptInput.value.trim();
510
+ const model = modelSelect.value;
511
+ const size = parseInt(imageSizeSelect.value);
512
+ const number = parseInt(imageCountSelect.value);
513
+
514
+ if (!prompt) {
515
+ promptInput.style.borderColor = 'red';
516
+ promptInput.classList.add('animate__animated', 'animate__shakeX');
517
+ setTimeout(() => {
518
+ promptInput.style.borderColor = '';
519
+ promptInput.classList.remove('animate__animated', 'animate__shakeX');
520
+ }, 1000);
521
+ return;
522
+ }
523
+
524
+ // Show loading state
525
+ resultDiv.style.display = 'none';
526
+ errorDiv.style.display = 'none';
527
+ loadingDiv.style.display = 'flex';
528
+ generateBtn.disabled = true;
529
+
530
+ try {
531
+ const response = await fetch('https://parthsadaria-lokiai.hf.space/images/generations', {
532
+ method: 'POST',
533
+ headers: {
534
+ 'Content-Type': 'application/json',
535
+ },
536
+ body: JSON.stringify({
537
+ model: model,
538
+ prompt: prompt,
539
+ size: size,
540
+ number: number
541
+ })
542
+ });
543
+
544
+ if (!response.ok) {
545
+ throw new Error('API request failed');
546
+ }
547
+
548
+ const data = await response.json();
549
+
550
+ // Display result
551
+ loadingDiv.style.display = 'none';
552
+ resultDiv.style.display = 'block';
553
+ modelUsed.textContent = model;
554
+
555
+ // Clear previous images
556
+ imagesContainer.innerHTML = '';
557
+
558
+ // Trigger confetti animation
559
+ createConfetti();
560
+
561
+ // Set grid columns based on number of images
562
+ if (number > 1) {
563
+ imagesContainer.className = 'images-grid multi-column';
564
+ } else {
565
+ imagesContainer.className = 'images-grid';
566
+ }
567
+
568
+ // Add generated images
569
+ if (data.data && data.data.length > 0) {
570
+ data.data.forEach((item, index) => {
571
+ const imgWrapper = document.createElement('div');
572
+ imgWrapper.className = 'image-wrapper animate__animated animate__zoomIn';
573
+ imgWrapper.style.animationDelay = `${index * 0.2}s`;
574
+
575
+ const img = document.createElement('img');
576
+ img.src = item.url;
577
+ img.alt = `Generated image ${index + 1}`;
578
+
579
+ const downloadBtn = document.createElement('button');
580
+ downloadBtn.className = 'btn-download';
581
+ downloadBtn.innerHTML = `
582
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
583
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
584
+ <polyline points="7 10 12 15 17 10"></polyline>
585
+ <line x1="12" y1="15" x2="12" y2="3"></line>
586
+ </svg>
587
+ `;
588
+
589
+ downloadBtn.addEventListener('click', () => {
590
+ const a = document.createElement('a');
591
+ a.href = item.url;
592
+ a.download = `loki-ai-${model}-${index + 1}.jpg`;
593
+ document.body.appendChild(a);
594
+ a.click();
595
+ document.body.removeChild(a);
596
+ });
597
+
598
+ imgWrapper.appendChild(img);
599
+ imgWrapper.appendChild(downloadBtn);
600
+ imagesContainer.appendChild(imgWrapper);
601
  });
602
+ }
603
+
604
+ } catch (error) {
605
+ console.error('Error:', error);
606
+ loadingDiv.style.display = 'none';
607
+ errorDiv.style.display = 'block';
608
+ errorDiv.classList.add('animate__animated', 'animate__fadeIn');
609
+ } finally {
610
+ generateBtn.disabled = false;
611
+ }
612
+ });
613
+
614
+ // Enter key to generate
615
+ promptInput.addEventListener('keypress', (e) => {
616
+ if (e.key === 'Enter') {
617
+ generateBtn.click();
618
+ }
619
+ });
620
+ });
621
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  </body>
623
+ </html>