Abhi1907 commited on
Commit
14fc3dd
·
verified ·
1 Parent(s): 2e4e1fc

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +751 -19
index.html CHANGED
@@ -1,19 +1,751 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Z-Image Turbo | AI Image Generator</title>
7
+ <!-- Importing FontAwesome for Icons -->
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+
10
+ <style>
11
+ :root {
12
+ /* Color Palette - Cyberpunk/Dark Mode */
13
+ --bg-color: #0f1115;
14
+ --panel-bg: #181b21;
15
+ --input-bg: #22262e;
16
+ --primary: #6366f1; /* Indigo */
17
+ --primary-hover: #4f46e5;
18
+ --accent: #ec4899; /* Pink */
19
+ --text-main: #ffffff;
20
+ --text-muted: #9ca3af;
21
+ --border-color: #2d313a;
22
+ --success: #10b981;
23
+ --radius-md: 12px;
24
+ --radius-sm: 8px;
25
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
26
+ --glow: 0 0 15px rgba(99, 102, 241, 0.3);
27
+ }
28
+
29
+ * {
30
+ box-sizing: border-box;
31
+ margin: 0;
32
+ padding: 0;
33
+ font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
34
+ }
35
+
36
+ body {
37
+ background-color: var(--bg-color);
38
+ color: var(--text-main);
39
+ min-height: 100vh;
40
+ display: flex;
41
+ flex-direction: column;
42
+ overflow-x: hidden;
43
+ }
44
+
45
+ /* --- Header --- */
46
+ header {
47
+ background-color: rgba(15, 17, 21, 0.9);
48
+ backdrop-filter: blur(10px);
49
+ border-bottom: 1px solid var(--border-color);
50
+ padding: 1rem 2rem;
51
+ position: sticky;
52
+ top: 0;
53
+ z-index: 100;
54
+ display: flex;
55
+ justify-content: space-between;
56
+ align-items: center;
57
+ }
58
+
59
+ .brand {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 10px;
63
+ font-size: 1.5rem;
64
+ font-weight: 700;
65
+ background: linear-gradient(to right, var(--primary), var(--accent));
66
+ -webkit-background-clip: text;
67
+ -webkit-text-fill-color: transparent;
68
+ letter-spacing: -0.5px;
69
+ }
70
+
71
+ .brand i {
72
+ -webkit-text-fill-color: var(--primary);
73
+ font-size: 1.2rem;
74
+ }
75
+
76
+ .anycoder-link {
77
+ font-size: 0.9rem;
78
+ color: var(--text-muted);
79
+ text-decoration: none;
80
+ transition: color 0.3s ease;
81
+ border: 1px solid var(--border-color);
82
+ padding: 0.4rem 0.8rem;
83
+ border-radius: var(--radius-sm);
84
+ background: var(--panel-bg);
85
+ }
86
+
87
+ .anycoder-link:hover {
88
+ color: var(--primary);
89
+ border-color: var(--primary);
90
+ }
91
+
92
+ /* --- Main Layout --- */
93
+ main {
94
+ flex: 1;
95
+ display: grid;
96
+ grid-template-columns: 350px 1fr;
97
+ gap: 2rem;
98
+ padding: 2rem;
99
+ max-width: 1600px;
100
+ margin: 0 auto;
101
+ width: 100%;
102
+ }
103
+
104
+ /* --- Sidebar / Controls --- */
105
+ .controls-panel {
106
+ background: var(--panel-bg);
107
+ border-radius: var(--radius-md);
108
+ padding: 1.5rem;
109
+ border: 1px solid var(--border-color);
110
+ height: fit-content;
111
+ box-shadow: var(--shadow);
112
+ display: flex;
113
+ flex-direction: column;
114
+ gap: 1.5rem;
115
+ }
116
+
117
+ .control-group {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 0.5rem;
121
+ }
122
+
123
+ label {
124
+ font-size: 0.85rem;
125
+ font-weight: 600;
126
+ color: var(--text-muted);
127
+ text-transform: uppercase;
128
+ letter-spacing: 0.5px;
129
+ }
130
+
131
+ textarea {
132
+ background: var(--input-bg);
133
+ border: 1px solid var(--border-color);
134
+ border-radius: var(--radius-sm);
135
+ color: var(--text-main);
136
+ padding: 1rem;
137
+ resize: vertical;
138
+ min-height: 120px;
139
+ font-size: 1rem;
140
+ transition: border-color 0.3s;
141
+ }
142
+
143
+ textarea:focus {
144
+ outline: none;
145
+ border-color: var(--primary);
146
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);
147
+ }
148
+
149
+ select, input[type="text"] {
150
+ background: var(--input-bg);
151
+ border: 1px solid var(--border-color);
152
+ border-radius: var(--radius-sm);
153
+ color: var(--text-main);
154
+ padding: 0.75rem;
155
+ font-size: 0.95rem;
156
+ width: 100%;
157
+ }
158
+
159
+ select:focus, input[type="text"]:focus {
160
+ outline: none;
161
+ border-color: var(--primary);
162
+ }
163
+
164
+ .ratio-grid {
165
+ display: grid;
166
+ grid-template-columns: repeat(3, 1fr);
167
+ gap: 0.5rem;
168
+ }
169
+
170
+ .ratio-btn {
171
+ background: var(--input-bg);
172
+ border: 1px solid var(--border-color);
173
+ color: var(--text-muted);
174
+ padding: 0.6rem;
175
+ border-radius: var(--radius-sm);
176
+ cursor: pointer;
177
+ transition: all 0.2s;
178
+ display: flex;
179
+ flex-direction: column;
180
+ align-items: center;
181
+ gap: 4px;
182
+ }
183
+
184
+ .ratio-btn i {
185
+ font-size: 1.2rem;
186
+ }
187
+
188
+ .ratio-btn span {
189
+ font-size: 0.7rem;
190
+ }
191
+
192
+ .ratio-btn:hover {
193
+ background: var(--border-color);
194
+ }
195
+
196
+ .ratio-btn.active {
197
+ background: rgba(99, 102, 241, 0.1);
198
+ border-color: var(--primary);
199
+ color: var(--primary);
200
+ }
201
+
202
+ .generate-btn {
203
+ background: linear-gradient(135deg, var(--primary), var(--accent));
204
+ color: white;
205
+ border: none;
206
+ padding: 1rem;
207
+ border-radius: var(--radius-sm);
208
+ font-size: 1rem;
209
+ font-weight: 700;
210
+ cursor: pointer;
211
+ transition: transform 0.2s, box-shadow 0.2s;
212
+ display: flex;
213
+ justify-content: center;
214
+ align-items: center;
215
+ gap: 0.5rem;
216
+ box-shadow: var(--glow);
217
+ }
218
+
219
+ .generate-btn:hover {
220
+ transform: translateY(-2px);
221
+ box-shadow: 0 0 25px rgba(99, 102, 241, 0.5);
222
+ }
223
+
224
+ .generate-btn:active {
225
+ transform: translateY(0);
226
+ }
227
+
228
+ .generate-btn:disabled {
229
+ opacity: 0.7;
230
+ cursor: not-allowed;
231
+ transform: none;
232
+ }
233
+
234
+ /* --- Preview Area --- */
235
+ .preview-panel {
236
+ display: flex;
237
+ flex-direction: column;
238
+ gap: 1.5rem;
239
+ }
240
+
241
+ .image-container {
242
+ background: var(--panel-bg);
243
+ border-radius: var(--radius-md);
244
+ border: 1px solid var(--border-color);
245
+ min-height: 500px;
246
+ display: flex;
247
+ justify-content: center;
248
+ align-items: center;
249
+ position: relative;
250
+ overflow: hidden;
251
+ box-shadow: var(--shadow);
252
+ }
253
+
254
+ .generated-image {
255
+ max-width: 100%;
256
+ max-height: 600px;
257
+ object-fit: contain;
258
+ opacity: 0;
259
+ transition: opacity 0.5s ease;
260
+ }
261
+
262
+ .generated-image.loaded {
263
+ opacity: 1;
264
+ }
265
+
266
+ .placeholder-text {
267
+ position: absolute;
268
+ color: var(--text-muted);
269
+ text-align: center;
270
+ display: flex;
271
+ flex-direction: column;
272
+ align-items: center;
273
+ gap: 1rem;
274
+ }
275
+
276
+ .placeholder-text i {
277
+ font-size: 3rem;
278
+ opacity: 0.3;
279
+ }
280
+
281
+ /* Loading State */
282
+ .loader-overlay {
283
+ position: absolute;
284
+ inset: 0;
285
+ background: rgba(15, 17, 21, 0.8);
286
+ display: none;
287
+ flex-direction: column;
288
+ justify-content: center;
289
+ align-items: center;
290
+ z-index: 10;
291
+ backdrop-filter: blur(5px);
292
+ }
293
+
294
+ .loader-overlay.active {
295
+ display: flex;
296
+ }
297
+
298
+ .spinner {
299
+ width: 50px;
300
+ height: 50px;
301
+ border: 3px solid rgba(255, 255, 255, 0.1);
302
+ border-radius: 50%;
303
+ border-top-color: var(--primary);
304
+ animation: spin 1s ease-in-out infinite;
305
+ margin-bottom: 1rem;
306
+ }
307
+
308
+ @keyframes spin {
309
+ to { transform: rotate(360deg); }
310
+ }
311
+
312
+ .loading-text {
313
+ font-family: monospace;
314
+ color: var(--primary);
315
+ font-size: 0.9rem;
316
+ }
317
+
318
+ /* Action Bar */
319
+ .action-bar {
320
+ display: flex;
321
+ justify-content: flex-end;
322
+ gap: 1rem;
323
+ opacity: 0.5;
324
+ pointer-events: none;
325
+ transition: opacity 0.3s;
326
+ }
327
+
328
+ .action-bar.active {
329
+ opacity: 1;
330
+ pointer-events: all;
331
+ }
332
+
333
+ .action-btn {
334
+ background: var(--input-bg);
335
+ border: 1px solid var(--border-color);
336
+ color: var(--text-main);
337
+ padding: 0.6rem 1.2rem;
338
+ border-radius: var(--radius-sm);
339
+ cursor: pointer;
340
+ display: flex;
341
+ align-items: center;
342
+ gap: 0.5rem;
343
+ font-size: 0.9rem;
344
+ transition: all 0.2s;
345
+ }
346
+
347
+ .action-btn:hover {
348
+ background: var(--border-color);
349
+ color: white;
350
+ }
351
+
352
+ .action-btn.primary {
353
+ background: var(--primary);
354
+ border-color: var(--primary);
355
+ }
356
+
357
+ .action-btn.primary:hover {
358
+ background: var(--primary-hover);
359
+ }
360
+
361
+ /* History Grid */
362
+ .history-section h3 {
363
+ margin-bottom: 1rem;
364
+ font-size: 1.1rem;
365
+ color: var(--text-main);
366
+ }
367
+
368
+ .history-grid {
369
+ display: grid;
370
+ grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
371
+ gap: 1rem;
372
+ }
373
+
374
+ .history-item {
375
+ aspect-ratio: 1;
376
+ border-radius: var(--radius-sm);
377
+ overflow: hidden;
378
+ cursor: pointer;
379
+ border: 2px solid transparent;
380
+ transition: all 0.2s;
381
+ position: relative;
382
+ }
383
+
384
+ .history-item:hover {
385
+ transform: scale(1.05);
386
+ border-color: var(--primary);
387
+ }
388
+
389
+ .history-item img {
390
+ width: 100%;
391
+ height: 100%;
392
+ object-fit: cover;
393
+ }
394
+
395
+ /* Toast Notification */
396
+ .toast {
397
+ position: fixed;
398
+ bottom: 2rem;
399
+ right: 2rem;
400
+ background: var(--panel-bg);
401
+ border: 1px solid var(--border-color);
402
+ padding: 1rem 1.5rem;
403
+ border-radius: var(--radius-sm);
404
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
405
+ transform: translateY(100px);
406
+ opacity: 0;
407
+ transition: all 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
408
+ z-index: 1000;
409
+ display: flex;
410
+ align-items: center;
411
+ gap: 0.8rem;
412
+ }
413
+
414
+ .toast.show {
415
+ transform: translateY(0);
416
+ opacity: 1;
417
+ }
418
+
419
+ .toast i {
420
+ color: var(--success);
421
+ }
422
+
423
+ /* Responsive */
424
+ @media (max-width: 900px) {
425
+ main {
426
+ grid-template-columns: 1fr;
427
+ }
428
+
429
+ .controls-panel {
430
+ order: 2;
431
+ }
432
+
433
+ .preview-panel {
434
+ order: 1;
435
+ }
436
+ }
437
+ </style>
438
+ </head>
439
+ <body>
440
+
441
+ <header>
442
+ <div class="brand">
443
+ <i class="fa-solid fa-bolt"></i>
444
+ Z-Image Turbo
445
+ </div>
446
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
447
+ Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em; margin-left: 5px;"></i>
448
+ </a>
449
+ </header>
450
+
451
+ <main>
452
+ <!-- Sidebar Controls -->
453
+ <section class="controls-panel">
454
+ <div class="control-group">
455
+ <label for="prompt">Prompt</label>
456
+ <textarea id="prompt" placeholder="Describe the image you want to generate... e.g., A futuristic cyberpunk city with neon lights, 4k, highly detailed"></textarea>
457
+ </div>
458
+
459
+ <div class="control-group">
460
+ <label for="negative-prompt">Negative Prompt</label>
461
+ <input type="text" id="negative-prompt" placeholder="blur, low quality, distorted">
462
+ </div>
463
+
464
+ <div class="control-group">
465
+ <label>Aspect Ratio</label>
466
+ <div class="ratio-grid">
467
+ <button class="ratio-btn active" data-ratio="1:1" data-w="1024" data-h="1024">
468
+ <i class="fa-regular fa-square"></i>
469
+ <span>1:1</span>
470
+ </button>
471
+ <button class="ratio-btn" data-ratio="16:9" data-w="1280" data-h="720">
472
+ <i class="fa-solid fa-rectangle-wide"></i>
473
+ <span>16:9</span>
474
+ </button>
475
+ <button class="ratio-btn" data-ratio="9:16" data-w="720" data-h="1280">
476
+ <i class="fa-solid fa-mobile-screen"></i>
477
+ <span>9:16</span>
478
+ </button>
479
+ </div>
480
+ </div>
481
+
482
+ <div class="control-group">
483
+ <label for="style">Style Preset</label>
484
+ <select id="style">
485
+ <option value="none">None (Default)</option>
486
+ <option value="cinematic">Cinematic</option>
487
+ <option value="anime">Anime / Manga</option>
488
+ <option value="3d-model">3D Model</option>
489
+ <option value="digital-art">Digital Art</option>
490
+ <option value="photographic">Photographic</option>
491
+ </select>
492
+ </div>
493
+
494
+ <div class="control-group">
495
+ <label for="steps">Inference Steps</label>
496
+ <input type="range" id="steps" min="10" max="50" value="25" style="width: 100%; accent-color: var(--primary);">
497
+ <div style="display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--text-muted);">
498
+ <span>Fast</span>
499
+ <span id="steps-val">25</span>
500
+ <span>Quality</span>
501
+ </div>
502
+ </div>
503
+
504
+ <button id="generate-btn" class="generate-btn">
505
+ <i class="fa-solid fa-wand-magic-sparkles"></i> Generate Image
506
+ </button>
507
+ </section>
508
+
509
+ <!-- Preview Area -->
510
+ <section class="preview-panel">
511
+ <div class="image-container" id="image-container">
512
+ <div class="placeholder-text" id="placeholder">
513
+ <i class="fa-regular fa-image"></i>
514
+ <p>Enter a prompt and click Generate</p>
515
+ </div>
516
+
517
+ <div class="loader-overlay" id="loader">
518
+ <div class="spinner"></div>
519
+ <div class="loading-text" id="loading-text">Initializing Z-Image Turbo...</div>
520
+ </div>
521
+
522
+ <img src="" alt="Generated AI Art" class="generated-image" id="main-image">
523
+ </div>
524
+
525
+ <div class="action-bar" id="action-bar">
526
+ <button class="action-btn" id="copy-seed-btn">
527
+ <i class="fa-solid fa-fingerprint"></i> Copy Seed
528
+ </button>
529
+ <button class="action-btn primary" id="download-btn">
530
+ <i class="fa-solid fa-download"></i> Download HD
531
+ </button>
532
+ </div>
533
+
534
+ <div class="history-section">
535
+ <h3>Recent Generations</h3>
536
+ <div class="history-grid" id="history-grid">
537
+ <!-- History items will be injected here -->
538
+ </div>
539
+ </div>
540
+ </section>
541
+ </main>
542
+
543
+ <!-- Toast Notification -->
544
+ <div class="toast" id="toast">
545
+ <i class="fa-solid fa-circle-check"></i>
546
+ <span id="toast-message">Operation successful</span>
547
+ </div>
548
+
549
+ <script>
550
+ // DOM Elements
551
+ const promptInput = document.getElementById('prompt');
552
+ const negativePromptInput = document.getElementById('negative-prompt');
553
+ const generateBtn = document.getElementById('generate-btn');
554
+ const mainImage = document.getElementById('main-image');
555
+ const loader = document.getElementById('loader');
556
+ const loadingText = document.getElementById('loading-text');
557
+ const placeholder = document.getElementById('placeholder');
558
+ const actionBar = document.getElementById('action-bar');
559
+ const downloadBtn = document.getElementById('download-btn');
560
+ const copySeedBtn = document.getElementById('copy-seed-btn');
561
+ const historyGrid = document.getElementById('history-grid');
562
+ const ratioBtns = document.querySelectorAll('.ratio-btn');
563
+ const stepsInput = document.getElementById('steps');
564
+ const stepsVal = document.getElementById('steps-val');
565
+ const styleSelect = document.getElementById('style');
566
+ const toast = document.getElementById('toast');
567
+ const toastMessage = document.getElementById('toast-message');
568
+
569
+ // State
570
+ let currentSeed = '';
571
+ let currentWidth = 1024;
572
+ let currentHeight = 1024;
573
+ let isGenerating = false;
574
+
575
+ // Event Listeners for Aspect Ratio
576
+ ratioBtns.forEach(btn => {
577
+ btn.addEventListener('click', () => {
578
+ ratioBtns.forEach(b => b.classList.remove('active'));
579
+ btn.classList.add('active');
580
+ currentWidth = parseInt(btn.dataset.w);
581
+ currentHeight = parseInt(btn.dataset.h);
582
+ });
583
+ });
584
+
585
+ // Step Slider Update
586
+ stepsInput.addEventListener('input', (e) => {
587
+ stepsVal.textContent = e.target.value;
588
+ });
589
+
590
+ // Generate Button Logic
591
+ generateBtn.addEventListener('click', generateImage);
592
+
593
+ // Helper: Show Toast
594
+ function showToast(msg) {
595
+ toastMessage.textContent = msg;
596
+ toast.classList.add('show');
597
+ setTimeout(() => {
598
+ toast.classList.remove('show');
599
+ }, 3000);
600
+ }
601
+
602
+ // Helper: Generate a random seed based on prompt + random
603
+ function generateSeed(text) {
604
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
605
+ let result = text.replace(/[^a-zA-Z0-9]/g, '').substring(0, 10);
606
+ if (result.length < 5) result += 'zimageturbo'; // Fallback for short prompts
607
+
608
+ // Add randomness for unique generations of same prompt
609
+ const randomPart = Math.random().toString(36).substring(2, 7);
610
+ return result + randomPart;
611
+ }
612
+
613
+ async function generateImage() {
614
+ const prompt = promptInput.value.trim();
615
+ if (!prompt) {
616
+ showToast("Please enter a text prompt first.");
617
+ promptInput.focus();
618
+ return;
619
+ }
620
+
621
+ if (isGenerating) return;
622
+ isGenerating = true;
623
+
624
+ // UI Updates: Start Loading
625
+ generateBtn.disabled = true;
626
+ generateBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Generating...';
627
+ loader.classList.add('active');
628
+ placeholder.style.display = 'none';
629
+ mainImage.classList.remove('loaded');
630
+ actionBar.classList.remove('active');
631
+
632
+ // Simulate AI Steps for realism
633
+ const steps = [
634
+ "Encoding text prompt...",
635
+ "Initializing latent space...",
636
+ "Running Z-Image Turbo diffusion...",
637
+ "Denoising step 5/25...",
638
+ "Denoising step 15/25...",
639
+ "Upscaling result...",
640
+ "Finalizing render..."
641
+ ];
642
+
643
+ let stepIndex = 0;
644
+ const stepInterval = setInterval(() => {
645
+ if (stepIndex < steps.length) {
646
+ loadingText.textContent = steps[stepIndex];
647
+ stepIndex++;
648
+ }
649
+ }, 400);
650
+
651
+ // Calculate Seed and Construct URL
652
+ // Note: Using picsum.photos as a placeholder for the actual AI generation.
653
+ // In a real app, this would be a fetch() call to the Z-Image Turbo API.
654
+ currentSeed = generateSeed(prompt);
655
+
656
+ // We use the seed to get a deterministic image from picsum
657
+ // We use the width/height settings from the UI
658
+ const imageUrl = `https://picsum.photos/seed/${currentSeed}/${currentWidth}/${currentHeight}`;
659
+
660
+ // Wait for simulated processing time (min 2.5s)
661
+ await new Promise(r => setTimeout(r, 2500));
662
+ clearInterval(stepInterval);
663
+
664
+ // Load Image
665
+ mainImage.src = imageUrl;
666
+
667
+ mainImage.onload = () => {
668
+ // Reset UI
669
+ isGenerating = false;
670
+ generateBtn.disabled = false;
671
+ generateBtn.innerHTML = '<i class="fa-solid fa-wand-magic-sparkles"></i> Generate Image';
672
+ loader.classList.remove('active');
673
+ mainImage.classList.add('loaded');
674
+ actionBar.classList.add('active');
675
+ loadingText.textContent = "Initializing Z-Image Turbo..."; // Reset text
676
+
677
+ // Add to history
678
+ addToHistory(imageUrl);
679
+ showToast("Image generated successfully!");
680
+ };
681
+
682
+ mainImage.onerror = () => {
683
+ isGenerating = false;
684
+ generateBtn.disabled = false;
685
+ generateBtn.innerHTML = '<i class="fa-solid fa-wand-magic-sparkles"></i> Generate Image';
686
+ loader.classList.remove('active');
687
+ placeholder.style.display = 'flex';
688
+ showToast("Error generating image. Try again.");
689
+ };
690
+ }
691
+
692
+ function addToHistory(url) {
693
+ const item = document.createElement('div');
694
+ item.className = 'history-item';
695
+ item.innerHTML = `<img src="${url}" alt="History Item">`;
696
+
697
+ item.addEventListener('click', () => {
698
+ mainImage.src = url;
699
+ mainImage.classList.add('loaded');
700
+ placeholder.style.display = 'none';
701
+ actionBar.classList.add('active');
702
+ // In a real app, we'd restore the prompt/seed data here too
703
+ });
704
+
705
+ // Add to beginning
706
+ historyGrid.insertBefore(item, historyGrid.firstChild);
707
+
708
+ // Limit history to 8 items
709
+ if (historyGrid.children.length > 8) {
710
+ historyGrid.removeChild(historyGrid.lastChild);
711
+ }
712
+ }
713
+
714
+ // Download Functionality
715
+ downloadBtn.addEventListener('click', async () => {
716
+ if (!mainImage.src) return;
717
+
718
+ try {
719
+ // Fetch blob to avoid cross-origin taint issues on some browsers
720
+ const response = await fetch(mainImage.src);
721
+ const blob = await response.blob();
722
+ const url = window.URL.createObjectURL(blob);
723
+
724
+ const a = document.createElement('a');
725
+ a.style.display = 'none';
726
+ a.href = url;
727
+ a.download = `z-image-${currentSeed}.jpg`;
728
+ document.body.appendChild(a);
729
+ a.click();
730
+
731
+ window.URL.revokeObjectURL(url);
732
+ document.body.removeChild(a);
733
+ showToast("Download started");
734
+ } catch (err) {
735
+ console.error(err);
736
+ // Fallback: Open in new tab
737
+ window.open(mainImage.src, '_blank');
738
+ }
739
+ });
740
+
741
+ // Copy Seed Functionality
742
+ copySeedBtn.addEventListener('click', () => {
743
+ if (!currentSeed) return;
744
+ navigator.clipboard.writeText(currentSeed).then(() => {
745
+ showToast("Seed copied to clipboard");
746
+ });
747
+ });
748
+
749
+ </script>
750
+ </body>
751
+ </html>