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

Update image-playground.html

Browse files
Files changed (1) hide show
  1. image-playground.html +752 -311
image-playground.html CHANGED
@@ -1,328 +1,769 @@
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
- <script src="https://cdn.tailwindcss.com"></script>
9
- <style>
10
- * {
11
- font-family: 'DM Sans', sans-serif;
12
- }
13
-
14
- .loading {
15
- width: 40px;
16
- height: 40px;
17
- border: 4px solid #f3f3f3;
18
- border-bottom-color: #000;
19
- border-radius: 50%;
20
- animation: rotation 1.2s linear infinite;
21
- }
22
-
23
- .dark .loading {
24
- border-color: #333;
25
- border-bottom-color: #fff;
26
- }
27
-
28
- @keyframes rotation {
29
- 0% { transform: rotate(0deg); }
30
- 100% { transform: rotate(360deg); }
31
- }
32
-
33
- .image-container {
34
- border-radius: 8px;
35
- overflow: hidden;
36
- }
37
-
38
- .theme-toggle {
39
- position: relative;
40
- width: 48px;
41
- height: 24px;
42
- border-radius: 12px;
43
- background-color: #e5e5e5;
44
- cursor: pointer;
45
- transition: background-color 0.3s;
46
- }
47
-
48
- .dark .theme-toggle {
49
- background-color: #555;
50
- }
51
-
52
- .toggle-thumb {
53
- position: absolute;
54
- top: 2px;
55
- left: 2px;
56
- width: 20px;
57
- height: 20px;
58
- border-radius: 50%;
59
- background-color: white;
60
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
61
- transition: transform 0.3s;
62
- }
63
-
64
- .dark .toggle-thumb {
65
- transform: translateX(24px);
66
- }
67
-
68
- .dark {
69
- background-color: #121212;
70
- color: #f5f5f5;
71
- }
72
-
73
- .dark .card {
74
- background-color: #1e1e1e;
75
- border-color: rgba(255, 255, 255, 0.1);
76
- }
77
-
78
- .dark .form-input {
79
- background-color: #2d2d2d;
80
- color: #f5f5f5;
81
- border-color: #444;
82
- }
83
-
84
- .dark .btn-primary {
85
- background-color: #f5f5f5;
86
- color: #121212;
87
- }
88
-
89
- .dark .btn-secondary {
90
- background-color: #2d2d2d;
91
- color: #f5f5f5;
92
- border: 1px solid #444;
93
- }
94
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  </head>
96
- <body class="p-4 md:p-6 bg-gray-50 dark:bg-gray-900 transition-colors duration-200">
97
- <div class="max-w-4xl mx-auto">
98
- <div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition-colors duration-200">
99
- <div class="flex flex-col md:flex-row items-center justify-between mb-6">
100
- <h1 class="text-3xl font-bold text-black dark:text-white mb-2 md:mb-0">LOKI.AI IMAGE PLAYGROUND</h1>
101
- <div class="flex items-center space-x-4">
102
- <div class="text-sm text-gray-500 dark:text-gray-400">Theme</div>
103
- <div id="theme-toggle" class="theme-toggle">
104
- <div class="toggle-thumb"></div>
105
- </div>
106
- </div>
107
- </div>
108
-
109
- <div class="space-y-4">
110
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
111
- <div>
112
- <label for="model" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Select Model</label>
113
- <div class="relative">
114
- <select id="model" class="form-input block w-full px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white text-gray-900 dark:text-white appearance-none">
115
- <option value="Flux Realism">Flux Realism</option>
116
- <option value="Flux Pro Ultra">Flux Pro Ultra</option>
117
- <option value="grok-2-aurora">grok-2-aurora</option>
118
- <option value="Flux Pro">Flux Pro</option>
119
- <option value="Flux Pro Ultra Raw">Flux Pro Ultra Raw</option>
120
- <option value="Flux Dev">Flux Dev</option>
121
- <option value="Flux Schnell">Flux Schnell</option>
122
- <option value="stable-diffusion-3-large-turbo">stable-diffusion-3-large-turbo</option>
123
- <option value="sdxl-lightning-4step">sdxl-lightning-4step</option>
124
- <option value="dall-e-3">dall-e-3</option>
125
- </select>
126
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 dark:text-gray-300">
127
- <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
128
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
129
- </svg>
130
- </div>
131
  </div>
132
- </div>
133
- <div>
134
- <label for="prompt" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Enter Prompt</label>
135
- <input type="text" id="prompt" placeholder="Describe what you want to see..." class="form-input block w-full px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white text-gray-900 dark:text-white" value="sky">
136
- </div>
137
  </div>
138
 
139
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-2">
140
- <div>
141
- <label for="image-size" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Image Size</label>
142
- <select id="image-size" class="form-input block w-full px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white text-gray-900 dark:text-white appearance-none">
143
- <option value="512">512 x 512</option>
144
- <option value="768">768 x 768</option>
145
- <option value="1024" selected>1024 x 1024</option>
146
- <option value="1536">1536 x 1536</option>
147
- </select>
148
- </div>
149
- <div>
150
- <label for="image-count" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Number of Images</label>
151
- <select id="image-count" class="form-input block w-full px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-1 focus:ring-black dark:focus:ring-white text-gray-900 dark:text-white appearance-none">
152
- <option value="1" selected>1</option>
153
- <option value="2">2</option>
154
- <option value="4">4</option>
155
- </select>
156
- </div>
157
- <div class="flex items-end">
158
- <button id="generate" class="btn-primary w-full bg-black dark:bg-white text-white dark:text-black px-6 py-2 rounded-lg font-medium hover:bg-gray-800 dark:hover:bg-gray-200 transition">
159
- Generate Image
160
- </button>
161
- </div>
162
- </div>
 
 
 
 
 
163
 
164
- <div id="result" class="mt-6 hidden">
165
- <div class="text-center mb-4">
166
- <h2 class="text-lg font-medium dark:text-white">Your Creation</h2>
167
- <p class="text-sm text-gray-500 dark:text-gray-400">Created with <span id="model-used"></span></p>
168
- </div>
169
- <div id="images-container" class="grid grid-cols-1 md:grid-cols-2 gap-4">
170
- <!-- Images will be inserted here dynamically -->
171
- </div>
172
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- <div id="loading" class="flex flex-col items-center justify-center py-6 hidden">
175
- <div class="loading mb-3"></div>
176
- <p class="text-gray-600 dark:text-gray-400 text-sm">Creating your image...</p>
177
- </div>
 
 
 
 
178
 
179
- <div id="error" class="bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-400 p-3 rounded-lg hidden">
180
- <p class="font-medium">Oops! Something went wrong.</p>
181
- <p class="text-sm">Please try again or check your connection.</p>
 
 
 
 
 
 
182
  </div>
183
- </div>
184
  </div>
185
-
186
- <div class="text-center text-gray-400 dark:text-gray-600 text-xs mt-4">
187
- © 2025 LOKI.AI IMAGE PLAYGROUND | All rights reserved
188
  </div>
189
- </div>
190
-
191
- <script>
192
- document.addEventListener('DOMContentLoaded', () => {
193
- // Elements
194
- const themeToggle = document.getElementById('theme-toggle');
195
- const generateBtn = document.getElementById('generate');
196
- const promptInput = document.getElementById('prompt');
197
- const modelSelect = document.getElementById('model');
198
- const imageSizeSelect = document.getElementById('image-size');
199
- const imageCountSelect = document.getElementById('image-count');
200
- const resultDiv = document.getElementById('result');
201
- const loadingDiv = document.getElementById('loading');
202
- const errorDiv = document.getElementById('error');
203
- const imagesContainer = document.getElementById('images-container');
204
- const modelUsed = document.getElementById('model-used');
205
-
206
- // Theme Toggle
207
- themeToggle.addEventListener('click', () => {
208
- document.documentElement.classList.toggle('dark');
209
- localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light');
210
- });
211
-
212
- // Check for saved theme preference
213
- if (localStorage.getItem('theme') === 'dark' ||
214
- (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
215
- document.documentElement.classList.add('dark');
216
- } else {
217
- document.documentElement.classList.remove('dark');
218
- }
219
-
220
- // Generate image
221
- generateBtn.addEventListener('click', async () => {
222
- const prompt = promptInput.value.trim();
223
- const model = modelSelect.value;
224
- const size = parseInt(imageSizeSelect.value);
225
- const number = parseInt(imageCountSelect.value);
226
-
227
- if (!prompt) {
228
- promptInput.style.borderColor = 'red';
229
- setTimeout(() => {
230
- promptInput.style.borderColor = '';
231
- }, 1500);
232
- return;
233
- }
234
-
235
- // Show loading state
236
- resultDiv.classList.add('hidden');
237
- errorDiv.classList.add('hidden');
238
- loadingDiv.classList.remove('hidden');
239
- generateBtn.disabled = true;
240
-
241
- try {
242
- const response = await fetch('https://parthsadaria-lokiai.hf.space/images/generations', {
243
- method: 'POST',
244
- headers: {
245
- 'Content-Type': 'application/json',
246
- },
247
- body: JSON.stringify({
248
- model: model,
249
- prompt: prompt,
250
- size: size,
251
- number: number
252
- })
253
- });
254
-
255
- if (!response.ok) {
256
- throw new Error('API request failed');
257
- }
258
-
259
- const data = await response.json();
260
-
261
- // Display result
262
- loadingDiv.classList.add('hidden');
263
- resultDiv.classList.remove('hidden');
264
- modelUsed.textContent = model;
265
-
266
- // Clear previous images
267
- imagesContainer.innerHTML = '';
268
-
269
- // Add generated images
270
- if (data.images && data.images.length > 0) {
271
- // Set grid columns based on number of images
272
- if (number > 1) {
273
- imagesContainer.className = `grid grid-cols-1 ${number > 1 ? 'md:grid-cols-2' : ''} gap-4`;
274
  } else {
275
- imagesContainer.className = 'mx-auto max-w-lg';
276
  }
277
-
278
- data.images.forEach((imgSrc, index) => {
279
- const imgContainer = document.createElement('div');
280
- imgContainer.className = 'image-container relative';
281
-
282
- const img = document.createElement('img');
283
- img.src = imgSrc;
284
- img.className = 'w-full h-auto shadow-md';
285
- img.alt = `Generated image ${index + 1}`;
286
-
287
- const downloadBtn = document.createElement('button');
288
- downloadBtn.className = 'btn-secondary absolute bottom-3 right-3 bg-white dark:bg-gray-800 text-black dark:text-white p-2 rounded-full shadow-lg';
289
- downloadBtn.innerHTML = `
290
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
291
- <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>
292
- </svg>
293
- `;
294
-
295
- downloadBtn.addEventListener('click', () => {
296
- const a = document.createElement('a');
297
- a.href = imgSrc;
298
- a.download = `loki-ai-${model}-${index + 1}-${new Date().getTime()}.png`;
299
- document.body.appendChild(a);
300
- a.click();
301
- document.body.removeChild(a);
302
- });
303
-
304
- imgContainer.appendChild(img);
305
- imgContainer.appendChild(downloadBtn);
306
- imagesContainer.appendChild(imgContainer);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  });
308
- }
309
-
310
- } catch (error) {
311
- console.error('Error:', error);
312
- loadingDiv.classList.add('hidden');
313
- errorDiv.classList.remove('hidden');
314
- } finally {
315
- generateBtn.disabled = false;
316
- }
317
- });
318
-
319
- // Enter key to generate
320
- promptInput.addEventListener('keypress', (e) => {
321
- if (e.key === 'Enter') {
322
- generateBtn.click();
323
- }
324
- });
325
- });
326
- </script>
 
 
 
 
 
 
 
 
327
  </body>
328
- </html>
 
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>