Elias207 commited on
Commit
4f08889
·
verified ·
1 Parent(s): 56d110d

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +214 -1019
index.html CHANGED
@@ -3,122 +3,60 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI Video Studio - استودیو ویدیو هوش مصنوعی</title>
7
-
8
- <!-- بارگذاری فونت‌ها -->
9
- <link rel="preconnect" href="https://fonts.googleapis.com">
10
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
12
-
13
  <style>
14
- /* ========================================================== */
15
- /* == ENHANCED UI STYLES FOR AI VIDEO STUDIO == */
16
- /* ========================================================== */
17
- #imageToVideoApp {
18
  --app-font: 'Vazirmatn', sans-serif;
19
- --app-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
20
  --panel-bg: #FFFFFF;
21
- --panel-border: #E8EBF7;
22
- --input-bg: #F8FAFF;
23
- --input-border: #DDE2F0;
24
  --text-primary: #1A202C;
25
- --text-secondary: #4A5568;
26
- --text-tertiary: #718096;
27
  --accent-primary: #4A6CFA;
28
  --accent-primary-hover: #3553D6;
29
  --accent-primary-glow: rgba(74, 108, 250, 0.25);
30
  --accent-secondary: #0FD4A8;
 
31
  --danger-color: #e53e3e;
32
  --danger-color-hover: #c53030;
33
- --success-color: #38A169;
34
- --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.06);
35
- --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
36
- --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
37
- --shadow-xl: 0 12px 32px rgba(0, 0, 0, 0.15);
38
- --radius-card: 28px;
39
- --radius-btn: 16px;
40
- --radius-input: 14px;
41
- --transition-smooth: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
42
- font-family: var(--app-font);
43
- color: var(--text-primary);
44
- line-height: 1.6;
45
- direction: rtl;
46
- min-height: 100vh;
47
- position: relative;
48
- overflow-x: hidden;
49
- background: var(--app-bg);
50
  }
51
 
52
- * {
53
- margin: 0;
54
- padding: 0;
55
- box-sizing: border-box;
56
- }
57
 
58
  body {
 
 
 
59
  margin: 0;
60
- background: var(--app-bg);
61
- }
62
-
63
- @keyframes fadeIn {
64
- from { opacity: 0; transform: translateY(20px); }
65
- to { opacity: 1; transform: translateY(0); }
66
- }
67
- @keyframes spin {
68
- from { transform: rotate(0deg); }
69
- to { transform: rotate(360deg); }
70
- }
71
- @keyframes pulse {
72
- 0%, 100% { transform: scale(1); }
73
- 50% { transform: scale(1.02); }
74
- }
75
- @keyframes float {
76
- 0%, 100% { transform: translateY(0px); }
77
- 50% { transform: translateY(-10px); }
78
- }
79
-
80
- /* Glass Effect Backdrop */
81
- #imageToVideoApp::before {
82
- content: '';
83
- position: fixed;
84
- top: 0;
85
- left: 0;
86
- right: 0;
87
- bottom: 0;
88
- background:
89
- radial-gradient(circle at 20% 50%, rgba(74, 108, 250, 0.2) 0%, transparent 50%),
90
- radial-gradient(circle at 80% 20%, rgba(15, 212, 168, 0.2) 0%, transparent 50%),
91
- radial-gradient(circle at 40% 80%, rgba(102, 126, 234, 0.2) 0%, transparent 50%);
92
- z-index: -1;
93
- }
94
-
95
- /* Main Container */
96
- #imageToVideoApp .studio-container {
97
- width: 100%;
98
- max-width: 1400px;
99
- margin: 0 auto;
100
- padding: 40px 20px;
101
- position: relative;
102
- z-index: 1;
103
  }
 
104
 
105
- /* Enhanced Header */
106
- #imageToVideoApp .studio-header {
107
  position: relative;
108
  text-align: center;
109
- margin-bottom: 3rem;
110
- padding: 3rem 2rem;
111
  animation: fadeIn 0.8s 0.1s ease-out backwards;
112
  overflow: hidden;
113
- border-radius: var(--radius-card);
114
- background: rgba(255, 255, 255, 0.95);
115
- backdrop-filter: blur(20px);
116
- border: 1px solid rgba(255, 255, 255, 0.2);
117
- box-shadow:
118
- 0 20px 40px rgba(0, 0, 0, 0.1),
119
- inset 0 1px 0 rgba(255, 255, 255, 0.6);
120
  }
121
-
122
  #neural-network-canvas {
123
  position: absolute;
124
  top: 0;
@@ -126,867 +64,210 @@
126
  width: 100%;
127
  height: 100%;
128
  z-index: 1;
129
- opacity: 0.6;
130
  }
131
-
132
- #imageToVideoApp .studio-logo,
133
- #imageToVideoApp .studio-subtitle {
134
  position: relative;
135
  z-index: 2;
136
  }
137
-
138
- #imageToVideoApp .studio-logo {
139
- display: inline-flex;
140
- align-items: center;
141
- gap: 1.5rem;
142
- margin-bottom: 1.5rem;
143
- animation: float 3s ease-in-out infinite;
144
- }
145
 
146
- #imageToVideoApp .logo-icon {
147
- width: 80px;
148
- height: 80px;
149
- filter: drop-shadow(0 8px 16px rgba(74, 108, 250, 0.3));
150
- }
151
- #imageToVideoApp .logo-icon svg {
152
- width: 100%;
153
- height: 100%;
154
- animation: pulse 2s ease-in-out infinite;
155
- }
156
-
157
- #imageToVideoApp .studio-title {
158
- font-size: 3.5rem;
159
- font-weight: 900;
160
- letter-spacing: -2px;
161
- background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 50%, #667eea 100%);
162
  -webkit-background-clip: text;
163
  -webkit-text-fill-color: transparent;
164
- text-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
165
- margin: 0;
166
- }
167
-
168
- #imageToVideoApp .studio-subtitle {
169
- font-size: 1.3rem;
170
- color: var(--text-secondary);
171
- margin-top: 1rem;
172
- font-weight: 500;
173
- opacity: 0.9;
174
- }
175
-
176
- /* Enhanced Control Panel */
177
- #imageToVideoApp .control-panel {
178
- display: grid;
179
- grid-template-columns: 1fr 1fr;
180
- gap: 2.5rem;
181
- margin-bottom: 2.5rem;
182
- animation: fadeIn 0.8s 0.3s ease-out backwards;
183
- }
184
- @media (max-width: 768px) {
185
- #imageToVideoApp .control-panel {
186
- grid-template-columns: 1fr;
187
- gap: 2rem;
188
- }
189
  }
 
190
 
191
- /* Enhanced Studio Cards */
192
- #imageToVideoApp .studio-card {
193
- background: rgba(255, 255, 255, 0.95);
194
- backdrop-filter: blur(20px);
195
- border: 1px solid rgba(255, 255, 255, 0.2);
196
- border-radius: var(--radius-card);
197
  padding: 3rem;
198
- box-shadow:
199
- 0 20px 40px rgba(0, 0, 0, 0.1),
200
- inset 0 1px 0 rgba(255, 255, 255, 0.6);
201
- transition: var(--transition-smooth);
202
- position: relative;
203
- overflow: hidden;
204
- }
205
-
206
- #imageToVideoApp .studio-card::before {
207
- content: '';
208
- position: absolute;
209
- top: 0;
210
- left: -100%;
211
- width: 100%;
212
- height: 100%;
213
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
214
- transition: left 0.6s;
215
- }
216
-
217
- #imageToVideoApp .studio-card:hover {
218
- transform: translateY(-8px) scale(1.02);
219
- box-shadow:
220
- 0 30px 60px rgba(0, 0, 0, 0.15),
221
- inset 0 1px 0 rgba(255, 255, 255, 0.8);
222
- }
223
-
224
- #imageToVideoApp .studio-card:hover::before {
225
- left: 100%;
226
- }
227
-
228
- /* General Panel Styling */
229
- #imageToVideoApp .timeline-container,
230
- #imageToVideoApp .video-output-container,
231
- #imageToVideoApp .error-panel {
232
- grid-column: 1 / -1;
233
- background: rgba(255, 255, 255, 0.95);
234
- backdrop-filter: blur(20px);
235
- border: 1px solid rgba(255, 255, 255, 0.2);
236
  border-radius: var(--radius-card);
237
- padding: 3rem;
238
- margin-bottom: 2.5rem;
239
- box-shadow:
240
- 0 20px 40px rgba(0, 0, 0, 0.1),
241
- inset 0 1px 0 rgba(255, 255, 255, 0.6);
242
- display: none;
243
- }
244
- #imageToVideoApp .timeline-container.active,
245
- #imageToVideoApp .video-output-container.active,
246
- #imageToVideoApp .error-panel.active {
247
- display: block;
248
- animation: fadeIn 0.5s ease;
249
- }
250
-
251
- /* Enhanced Section Headers */
252
- #imageToVideoApp .section-header {
253
- display: flex;
254
- align-items: center;
255
- gap: 1rem;
256
- margin-bottom: 2rem;
257
- padding-bottom: 1.5rem;
258
- border-bottom: 2px solid rgba(74, 108, 250, 0.1);
259
- position: relative;
260
- }
261
-
262
- #imageToVideoApp .section-header::after {
263
- content: '';
264
- position: absolute;
265
- bottom: -2px;
266
- left: 0;
267
- width: 60px;
268
- height: 2px;
269
- background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
270
- border-radius: 1px;
271
- }
272
-
273
- #imageToVideoApp .section-icon {
274
- width: 32px;
275
- height: 32px;
276
- color: var(--accent-primary);
277
- filter: drop-shadow(0 2px 4px rgba(74, 108, 250, 0.3));
278
- }
279
- #imageToVideoApp .section-title {
280
- font-size: 1.4rem;
281
- font-weight: 800;
282
- color: var(--text-primary);
283
- background: linear-gradient(135deg, var(--text-primary), var(--accent-primary));
284
- -webkit-background-clip: text;
285
- -webkit-text-fill-color: transparent;
286
  }
287
 
288
- /* Enhanced Upload Zone */
289
- #imageToVideoApp .upload-zone {
290
- position: relative;
291
- width: 100%;
292
- aspect-ratio: 16/9;
293
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
294
- border: 3px dashed var(--input-border);
295
- border-radius: var(--radius-input);
296
  display: flex;
297
  align-items: center;
298
- justify-content: center;
299
- cursor: pointer;
300
- overflow: hidden;
301
- transition: var(--transition-smooth);
302
- text-align: center;
303
- position: relative;
304
- }
305
-
306
- #imageToVideoApp .upload-zone::before {
307
- content: '';
308
- position: absolute;
309
- top: 0;
310
- left: 0;
311
- right: 0;
312
- bottom: 0;
313
- background:
314
- radial-gradient(circle at 30% 30%, rgba(74, 108, 250, 0.05) 0%, transparent 50%),
315
- radial-gradient(circle at 70% 70%, rgba(15, 212, 168, 0.05) 0%, transparent 50%);
316
- z-index: 1;
317
- }
318
-
319
- #imageToVideoApp .upload-zone:hover:not(.has-image),
320
- #imageToVideoApp .upload-zone.drag-over {
321
- border-color: var(--accent-primary);
322
- background: linear-gradient(135deg, #fff 0%, rgba(74, 108, 250, 0.05) 100%);
323
- box-shadow:
324
- 0 0 30px var(--accent-primary-glow),
325
- inset 0 1px 0 rgba(255, 255, 255, 0.8);
326
- transform: scale(1.02);
327
- }
328
-
329
- #imageToVideoApp .upload-content {
330
- display: flex;
331
- flex-direction: column;
332
- align-items: center;
333
- gap: 1.5rem;
334
- position: relative;
335
- z-index: 2;
336
- }
337
-
338
- #imageToVideoApp .upload-icon-wrapper {
339
- padding: 1.5rem;
340
- background: linear-gradient(135deg, rgba(74, 108, 250, 0.1) 0%, rgba(15, 212, 168, 0.1) 100%);
341
- border-radius: 50%;
342
- animation: pulse 2s ease-in-out infinite;
343
- }
344
-
345
- #imageToVideoApp .upload-icon-wrapper svg {
346
- width: 60px;
347
- height: 60px;
348
- color: var(--accent-primary);
349
- stroke-width: 1.5;
350
- filter: drop-shadow(0 4px 8px rgba(74, 108, 250, 0.3));
351
- }
352
-
353
- #imageToVideoApp .upload-title {
354
- font-size: 1.3rem;
355
- font-weight: 700;
356
- color: var(--text-primary);
357
- margin-bottom: 0;
358
- }
359
- #imageToVideoApp .upload-subtitle {
360
- font-size: 1rem;
361
- color: var(--text-secondary);
362
- font-weight: 500;
363
- }
364
- #imageToVideoApp #imageFile { display: none; }
365
- #imageToVideoApp #imagePreview {
366
- position: absolute;
367
- top: 0;
368
- left: 0;
369
- width: 100%;
370
- height: 100%;
371
- object-fit: contain;
372
- border-radius: var(--radius-input);
373
- }
374
- #imageToVideoApp .upload-zone.has-image {
375
- border-style: solid;
376
- border-color: var(--success-color);
377
- padding: 0;
378
- box-shadow: 0 0 20px rgba(56, 161, 105, 0.3);
379
- }
380
- #imageToVideoApp .upload-zone.has-image .upload-content { display: none; }
381
-
382
- /* Enhanced Prompt Input */
383
- #imageToVideoApp .prompt-textarea {
384
- width: 100%;
385
- min-height: 140px;
386
- padding: 1.5rem;
387
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
388
- border: 2px solid var(--input-border);
389
- border-radius: var(--radius-input);
390
- color: var(--text-primary);
391
- font-family: inherit;
392
- font-size: 1.1rem;
393
- resize: vertical;
394
- transition: var(--transition-smooth);
395
- box-shadow:
396
- var(--shadow-sm) inset,
397
- 0 4px 12px rgba(0, 0, 0, 0.05);
398
- line-height: 1.6;
399
- }
400
-
401
- #imageToVideoApp .prompt-textarea:focus {
402
- outline: none;
403
- border-color: var(--accent-primary);
404
- background: #fff;
405
- box-shadow:
406
- 0 0 0 4px var(--accent-primary-glow),
407
- var(--shadow-md) inset;
408
- transform: scale(1.01);
409
- }
410
-
411
- #imageToVideoApp .prompt-textarea::placeholder {
412
- color: var(--text-tertiary);
413
- font-style: italic;
414
- }
415
-
416
- /* Enhanced Generate Button */
417
- #imageToVideoApp .generate-button {
418
- width: 100%;
419
- padding: 1.5rem 2rem;
420
- background: linear-gradient(135deg, var(--accent-secondary) 0%, var(--accent-primary) 50%, #667eea 100%);
421
- border: none;
422
- border-radius: var(--radius-btn);
423
- color: white;
424
- font-size: 1.4rem;
425
- font-weight: 800;
426
- cursor: pointer;
427
- display: flex;
428
- align-items: center;
429
- justify-content: center;
430
- gap: 1rem;
431
- transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
432
- box-shadow:
433
- 0 8px 24px rgba(74, 108, 250, 0.4),
434
- 0 4px 12px rgba(15, 212, 168, 0.3),
435
- inset 0 1px 0 rgba(255, 255, 255, 0.3);
436
- margin-top: 2rem;
437
- position: relative;
438
- overflow: hidden;
439
- }
440
-
441
- #imageToVideoApp .generate-button::before {
442
- content: '';
443
- position: absolute;
444
- top: 0;
445
- left: -100%;
446
- width: 100%;
447
- height: 100%;
448
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
449
- transition: left 0.6s;
450
- }
451
-
452
- #imageToVideoApp .generate-button:hover:not(:disabled) {
453
- transform: translateY(-6px) scale(1.03);
454
- box-shadow:
455
- 0 12px 32px rgba(74, 108, 250, 0.5),
456
- 0 6px 16px rgba(15, 212, 168, 0.4),
457
- inset 0 1px 0 rgba(255, 255, 255, 0.4);
458
- }
459
-
460
- #imageToVideoApp .generate-button:hover:not(:disabled)::before {
461
- left: 100%;
462
- }
463
-
464
- #imageToVideoApp .generate-button:disabled {
465
- background: linear-gradient(135deg, var(--text-tertiary), #A0AEC0);
466
- cursor: not-allowed;
467
- transform: none;
468
- box-shadow: var(--shadow-md);
469
- opacity: 0.7;
470
- }
471
-
472
- #imageToVideoApp .generate-button svg {
473
- width: 28px;
474
- height: 28px;
475
- filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
476
- }
477
-
478
- /* Enhanced Progress Section */
479
- #imageToVideoApp .timeline-header {
480
- display: flex;
481
- align-items: center;
482
- justify-content: space-between;
483
- margin-bottom: 2.5rem;
484
- flex-wrap: wrap;
485
- gap: 1rem;
486
- }
487
-
488
- #imageToVideoApp .timeline-title {
489
- display: flex;
490
- align-items: center;
491
- gap: 1rem;
492
- font-size: 1.4rem;
493
- font-weight: 800;
494
- color: var(--text-primary);
495
- }
496
-
497
- #imageToVideoApp .timeline-status {
498
- padding: 8px 20px;
499
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
500
- border: 2px solid var(--input-border);
501
- border-radius: 25px;
502
- font-size: 0.9rem;
503
- color: var(--text-secondary);
504
  font-weight: 700;
505
- box-shadow: var(--shadow-sm);
506
- }
507
-
508
- #imageToVideoApp .film-timeline {
509
- height: 12px;
510
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
511
- border-radius: 6px;
512
- overflow: hidden;
513
- margin-bottom: 2rem;
514
- box-shadow: var(--shadow-sm) inset;
515
- border: 1px solid var(--input-border);
516
- }
517
-
518
- #imageToVideoApp .timeline-progress {
519
- height: 100%;
520
- background: linear-gradient(90deg, var(--accent-secondary) 0%, var(--accent-primary) 50%, #667eea 100%);
521
- transition: width 0.4s cubic-bezier(0.23, 1, 0.32, 1);
522
- border-radius: 6px;
523
- box-shadow: 0 0 20px rgba(74, 108, 250, 0.4);
524
- position: relative;
525
- }
526
-
527
- #imageToVideoApp .timeline-progress::after {
528
- content: '';
529
- position: absolute;
530
- top: 0;
531
- left: 0;
532
- right: 0;
533
- bottom: 0;
534
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
535
- animation: progress-shine 2s ease-in-out infinite;
536
- }
537
-
538
- @keyframes progress-shine {
539
- 0% { transform: translateX(-100%); }
540
- 100% { transform: translateX(100%); }
541
- }
542
-
543
- /* Enhanced Status Messages */
544
- #imageToVideoApp .status-container {
545
- max-height: 250px;
546
- overflow-y: auto;
547
- padding-left: 10px;
548
- }
549
-
550
- #imageToVideoApp .status-message {
551
- padding: 16px 20px;
552
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
553
- border-radius: var(--radius-input);
554
- margin-bottom: 12px;
555
- display: flex;
556
- align-items: center;
557
- gap: 15px;
558
- animation: fadeIn 0.4s ease-out;
559
- border-left: 4px solid var(--accent-primary);
560
- box-shadow: var(--shadow-sm);
561
- transition: var(--transition-smooth);
562
- }
563
-
564
- #imageToVideoApp .status-message:hover {
565
- transform: translateX(-5px);
566
- box-shadow: var(--shadow-md);
567
- }
568
-
569
- #imageToVideoApp .status-message.success {
570
- border-left-color: var(--success-color);
571
- background: linear-gradient(135deg, rgba(56, 161, 105, 0.1) 0%, rgba(56, 161, 105, 0.05) 100%);
572
- }
573
- #imageToVideoApp .status-message.error {
574
- border-left-color: var(--danger-color);
575
- background: linear-gradient(135deg, rgba(229, 62, 62, 0.1) 0%, rgba(229, 62, 62, 0.05) 100%);
576
- }
577
-
578
- #imageToVideoApp .status-icon {
579
- width: 24px;
580
- height: 24px;
581
- flex-shrink: 0;
582
- }
583
- #imageToVideoApp .status-text {
584
- font-size: 1rem;
585
- color: var(--text-secondary);
586
- font-weight: 500;
587
- }
588
-
589
- /* Enhanced Video Output */
590
- #imageToVideoApp .video-player {
591
- position: relative;
592
- width: 100%;
593
- max-width: 900px;
594
- margin: 0 auto;
595
- border-radius: var(--radius-input);
596
- overflow: hidden;
597
- box-shadow:
598
- 0 20px 40px rgba(0, 0, 0, 0.2),
599
- inset 0 1px 0 rgba(255, 255, 255, 0.2);
600
- border: 3px solid rgba(255, 255, 255, 0.3);
601
- }
602
-
603
- #imageToVideoApp #outputVideo {
604
- width: 100%;
605
- display: block;
606
- background: #000;
607
- }
608
-
609
- #imageToVideoApp .video-controls {
610
- display: flex;
611
- justify-content: center;
612
- gap: 2rem;
613
- margin-top: 2.5rem;
614
- flex-wrap: wrap;
615
- }
616
-
617
- #imageToVideoApp .video-button {
618
- padding: 1rem 2rem;
619
- border: none;
620
- border-radius: var(--radius-btn);
621
- font-size: 1.1rem;
622
- font-weight: 700;
623
- cursor: pointer;
624
- display: flex;
625
- align-items: center;
626
- gap: 12px;
627
- transition: var(--transition-smooth);
628
- font-family: var(--app-font);
629
- position: relative;
630
- overflow: hidden;
631
- }
632
-
633
- #imageToVideoApp .video-button::before {
634
- content: '';
635
- position: absolute;
636
- top: 0;
637
- left: -100%;
638
- width: 100%;
639
- height: 100%;
640
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
641
- transition: left 0.6s;
642
- }
643
-
644
- #imageToVideoApp .video-button:hover {
645
- transform: translateY(-4px) scale(1.05);
646
- }
647
-
648
- #imageToVideoApp .video-button:hover::before {
649
- left: 100%;
650
- }
651
-
652
- #imageToVideoApp .video-button.primary {
653
- background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
654
- color: white;
655
- box-shadow:
656
- 0 8px 20px rgba(74, 108, 250, 0.4),
657
- inset 0 1px 0 rgba(255, 255, 255, 0.3);
658
- }
659
- #imageToVideoApp .video-button.primary:hover {
660
- box-shadow:
661
- 0 12px 28px rgba(74, 108, 250, 0.5),
662
- inset 0 1px 0 rgba(255, 255, 255, 0.4);
663
- }
664
-
665
- #imageToVideoApp .video-button:not(.primary) {
666
- background: linear-gradient(135deg, var(--input-bg) 0%, rgba(248, 250, 255, 0.8) 100%);
667
- color: var(--text-secondary);
668
- border: 2px solid var(--input-border);
669
- box-shadow: var(--shadow-sm);
670
- }
671
- #imageToVideoApp .video-button:not(.primary):hover {
672
- background: linear-gradient(135deg, #fff 0%, var(--input-bg) 100%);
673
  color: var(--text-primary);
674
- box-shadow: var(--shadow-md);
675
- }
676
-
677
- /* Enhanced Error Panel */
678
- #imageToVideoApp .error-panel {
679
- background: linear-gradient(135deg, rgba(229, 62, 62, 0.1) 0%, rgba(229, 62, 62, 0.05) 100%);
680
- border-color: rgba(229, 62, 62, 0.3);
681
- }
682
-
683
- #imageToVideoApp .error-header {
684
- display: flex;
685
- align-items: center;
686
- gap: 15px;
687
- margin-bottom: 2rem;
688
- color: var(--danger-color);
689
- font-size: 1.4rem;
690
- font-weight: 800;
691
- }
692
-
693
- #imageToVideoApp .error-content {
694
- color: var(--text-secondary);
695
- line-height: 1.7;
696
- margin-bottom: 2.5rem;
697
- font-size: 1.1rem;
698
- }
699
-
700
- #imageToVideoApp .error-actions {
701
- display: flex;
702
- gap: 1.5rem;
703
- flex-wrap: wrap;
704
- }
705
-
706
- /* Enhanced Loading Spinner */
707
- #imageToVideoApp .spinner-container {
708
- display: flex;
709
- flex-direction: column;
710
- align-items: center;
711
- justify-content: center;
712
- padding: 3rem;
713
- }
714
-
715
- #imageToVideoApp .spinner {
716
- width: 50px;
717
- height: 50px;
718
- margin-bottom: 2rem;
719
- }
720
-
721
- #imageToVideoApp .spinner-ring {
722
- width: 100%;
723
- height: 100%;
724
- border-radius: 50%;
725
- border: 4px solid var(--input-border);
726
- border-top: 4px solid var(--accent-primary);
727
- border-right: 4px solid var(--accent-secondary);
728
- animation: spin 1s linear infinite;
729
- box-shadow: 0 0 20px rgba(74, 108, 250, 0.3);
730
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
731
 
732
- #imageToVideoApp .spinner-text {
733
- color: var(--text-secondary);
734
- font-size: 1.1rem;
735
- text-align: center;
736
- font-weight: 600;
737
- }
738
 
739
- /* Enhanced Responsive Design */
740
  @media (max-width: 768px) {
741
- #imageToVideoApp .studio-title { font-size: 2.8rem; }
742
- #imageToVideoApp .studio-container { padding: 20px 15px; }
743
- #imageToVideoApp .studio-card,
744
- #imageToVideoApp .timeline-container,
745
- #imageToVideoApp .video-output-container,
746
- #imageToVideoApp .error-panel { padding: 2rem; }
747
- #imageToVideoApp .logo-icon { width: 60px; height: 60px; }
748
- #imageToVideoApp .video-controls { gap: 1rem; }
749
- #imageToVideoApp .video-button { padding: 0.8rem 1.5rem; font-size: 1rem; }
750
- }
751
-
752
- /* Additional Enhancements */
753
- #imageToVideoApp .control-panel .studio-card:nth-child(1) {
754
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(74, 108, 250, 0.02) 100%);
755
- }
756
-
757
- #imageToVideoApp .control-panel .studio-card:nth-child(2) {
758
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(15, 212, 168, 0.02) 100%);
759
- }
760
-
761
- /* Scroll animations */
762
- @media (prefers-reduced-motion: no-preference) {
763
- #imageToVideoApp .studio-card {
764
- animation: fadeIn 0.6s ease-out backwards;
765
- }
766
- #imageToVideoApp .control-panel .studio-card:nth-child(1) {
767
- animation-delay: 0.2s;
768
- }
769
- #imageToVideoApp .control-panel .studio-card:nth-child(2) {
770
- animation-delay: 0.4s;
771
- }
772
  }
773
  </style>
774
  </head>
775
  <body>
776
-
777
- <div id="imageToVideoApp">
778
- <div class="studio-container">
779
-
780
- <header class="studio-header">
781
- <canvas id="neural-network-canvas"></canvas>
782
- <div class="studio-logo">
783
- <div class="logo-icon">
784
- <svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
785
- <!-- Enhanced Video Camera Icon -->
786
- <circle cx="50" cy="50" r="48" stroke="url(#grad1)" stroke-width="2" fill="url(#radialGrad)" opacity="0.1"/>
787
- <circle cx="50" cy="50" r="38" stroke="url(#grad1)" stroke-width="2" opacity="0.2"/>
788
- <circle cx="50" cy="50" r="28" stroke="url(#grad1)" stroke-width="2" opacity="0.3"/>
789
-
790
- <!-- Camera Body -->
791
- <rect x="25" y="35" width="35" height="30" rx="4" fill="url(#grad1)" opacity="0.8"/>
792
-
793
- <!-- Lens -->
794
- <circle cx="42.5" cy="50" r="12" fill="url(#grad2)" opacity="0.9"/>
795
- <circle cx="42.5" cy="50" r="8" stroke="white" stroke-width="2" fill="none"/>
796
- <circle cx="42.5" cy="50" r="4" fill="white" opacity="0.8"/>
797
-
798
- <!-- Viewfinder -->
799
- <rect x="58" y="42" width="8" height="16" rx="2" fill="url(#grad1)" opacity="0.7"/>
800
-
801
- <!-- Film strip elements -->
802
- <rect x="68" y="30" width="4" height="6" rx="1" fill="url(#grad1)" opacity="0.6"/>
803
- <rect x="68" y="40" width="4" height="6" rx="1" fill="url(#grad1)" opacity="0.6"/>
804
- <rect x="68" y="50" width="4" height="6" rx="1" fill="url(#grad1)" opacity="0.6"/>
805
- <rect x="68" y="60" width="4" height="6" rx="1" fill="url(#grad1)" opacity="0.6"/>
806
- <rect x="68" y="70" width="4" height="6" rx="1" fill="url(#grad1)" opacity="0.6"/>
807
-
808
- <!-- Play button overlay -->
809
- <polygon points="75,45 85,50 75,55" fill="white" opacity="0.9"/>
810
-
811
- <defs>
812
- <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
813
- <stop offset="0%" style="stop-color:#4A6CFA;stop-opacity:1" />
814
- <stop offset="50%" style="stop-color:#667eea;stop-opacity:1" />
815
- <stop offset="100%" style="stop-color:#0FD4A8;stop-opacity:1" />
816
- </linearGradient>
817
- <linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="100%">
818
- <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
819
- <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
820
- </linearGradient>
821
- <radialGradient id="radialGrad" cx="50%" cy="50%" r="50%">
822
- <stop offset="0%" style="stop-color:#4A6CFA;stop-opacity:0.3" />
823
- <stop offset="100%" style="stop-color:#0FD4A8;stop-opacity:0.1" />
824
- </radialGradient>
825
- </defs>
826
- </svg>
827
  </div>
828
- <h1 class="studio-title">AI Video Studio ✨</h1>
829
  </div>
830
- <p class="studio-subtitle">تصاویر خود را با قدرت هوش مصنوعی به ویدیو سینمایی تبدیل کنید</p>
831
- </header>
 
 
 
 
 
 
 
 
 
 
 
 
832
 
833
- <div class="control-panel">
834
- <div class="studio-card">
835
- <div class="section-header">
836
- <!-- Enhanced Image Upload Icon -->
837
- <svg class="section-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
838
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
839
- <circle cx="8.5" cy="8.5" r="1.5"/>
840
- <polyline points="21,15 16,10 5,21"/>
841
- <path d="M14 8l4 4"/>
842
- <path d="M10 12l6-6"/>
843
- </svg>
844
- <span class="section-title">۱. تصویر ورودی</span>
845
- </div>
846
-
847
- <div class="upload-zone" id="image-drop-zone">
848
- <input type="file" id="imageFile" accept="image/jpeg, image/png, image/webp" />
849
- <div class="upload-content">
850
- <div class="upload-icon-wrapper">
851
- <!-- Enhanced Upload Icon -->
852
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
853
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
854
- <polyline points="17 8 12 3 7 8"></polyline>
855
- <line x1="12" y1="3" x2="12" y2="15"></line>
856
- <circle cx="12" cy="12" r="1" fill="currentColor"/>
857
- </svg>
858
- </div>
859
- <h3 class="upload-title">بارگذاری تصویر</h3>
860
- <p class="upload-subtitle">تصویر را بکشید یا برای انتخاب کلیک کنید<br>فرمت‌های پشتیبانی شده: JPG, PNG, WebP</p>
861
- </div>
862
- <img id="imagePreview" src="" alt="Preview" />
863
- </div>
864
  </div>
 
865
 
866
- <div class="studio-card">
867
- <div class="section-header">
868
- <!-- Enhanced Magic Wand Icon -->
869
- <svg class="section-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
870
- <path d="M15 4V2m0 20v-2m-4-11V7m0 14v-2m8-8h2M1 12h2m18.5-6.5-1.5 1.5M3.5 18.5 5 17m12.5 1.5L16 17M5 7l1.5 1.5"/>
871
- <circle cx="12" cy="12" r="3"/>
872
- <path d="m8 21 8-11-8-2-2 8z"/>
873
- </svg>
874
- <span class="section-title">۲. دستور جادویی ساخت</span>
875
  </div>
876
-
877
- <div class="prompt-container">
878
- <textarea
879
- id="prompt"
880
- class="prompt-textarea"
881
- placeholder="نحوه حرکت دوربین، جزئیات انیمیشن و افکت‌های مورد نظر را توصیف کنید...
882
 
883
- مثال‌هایی از دستورات جذاب:
884
- زوم آهسته به بیرون در حالی که برگ‌ها در باد می‌رقصند
885
- حرکت سینمایی دوربین از چپ به راست با افکت پارالکس
886
- نورپردازی طلایی غروب با سایه‌های نرم در حال تغییر
887
- حرکت ملایم آب یا دود در پس‌زمینه"
888
- ></textarea>
 
 
 
 
 
 
 
889
  </div>
890
 
891
- <button id="generateButton" class="generate-button">
892
- <!-- Enhanced Magic/Video Icon -->
893
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
894
- <polygon points="23 7 16 12 23 17 23 7"></polygon>
895
- <rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>
896
- <path d="M8 9l3 3-3 3"/>
897
- </svg>
898
- ساخت ویدیو جادویی ✨
899
- </button>
900
- </div>
901
- </div>
902
-
903
- <div id="statusSection" class="timeline-container">
904
- <div class="timeline-header">
905
- <div class="timeline-title">
906
- <!-- Enhanced Processing Icon -->
907
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
908
- <circle cx="12" cy="12" r="3"/>
909
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
910
- </svg>
911
- پردازش هوشمند ویدیو
912
  </div>
913
- <div id="statusText" class="timeline-status">در حال پردازش جادویی...</div>
914
- </div>
915
-
916
- <div class="film-timeline">
917
- <div class="timeline-progress" id="progressBar" style="width: 0%"></div>
918
- </div>
919
-
920
- <div id="aiLoader" class="spinner-container" style="display: none;">
921
- <div class="spinner"><div class="spinner-ring"></div></div>
922
- <div id="aiLoaderText" class="spinner-text">هوش مصنوعی در حال ساخت شاهکار شما...</div>
923
- </div>
924
-
925
- <div id="statusMessages" class="status-container"></div>
926
- </div>
927
-
928
- <div id="outputSection" class="video-output-container">
929
- <div class="section-header" style="border-bottom:none; margin-bottom: 2rem;">
930
- <!-- Enhanced Result Icon -->
931
- <svg class="section-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
932
- <polygon points="5 3 19 12 5 21 5 3"></polygon>
933
- <path d="M19 12H5"/>
934
- <circle cx="19" cy="12" r="2"/>
935
- <path d="M5 12V3l14 9"/>
936
- </svg>
937
- <span class="section-title">۳. شاهکار نهایی شما 🎬</span>
938
- </div>
939
- <div class="video-player">
940
- <video id="outputVideo" controls preload="metadata" playsinline></video>
941
- </div>
942
-
943
- <p id="finalSeed" style="text-align: center; color: var(--text-tertiary); margin-top: 2rem; font-weight: 500;"></p>
944
- <div id="downloadLinkStatus" style="text-align: center; color: var(--text-secondary); margin-top: 1rem; font-weight: 500;"></div>
945
-
946
- <div class="video-controls">
947
- <button id="btnDownloadVideo" class="video-button primary" style="display: none;">
948
- <!-- Enhanced Download Icon -->
949
- <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
950
- <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
951
- <circle cx="12" cy="11" r="1" fill="white" opacity="0.8"/>
952
- </svg>
953
- دانلود شاهکار 🎬
954
- </button>
955
- <button id="btnRestart" class="video-button">
956
- <!-- Enhanced Restart Icon -->
957
- <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
958
- <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
959
- </svg>
960
- ساخت ویدیو جدید ✨
961
- </button>
962
- </div>
963
- </div>
964
 
965
- <div id="criticalErrorSection" class="error-panel">
966
- <div class="error-header">
967
- <!-- Enhanced Error Icon -->
968
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
969
- <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
970
- <line x1="12" y1="9" x2="12" y2="13"/>
971
- <line x1="12" y1="17" x2="12.01" y2="17"/>
972
- </svg>
973
- <span>خطا در پردازش</span>
974
- </div>
975
- <div id="criticalErrorMessage" class="error-content"></div>
976
- <div class="error-actions">
977
- <button id="btnCriticalErrorGoBack" class="video-button">بازگشت</button>
978
- <button id="btnCriticalErrorRetry" class="video-button primary">تلاش مجدد</button>
979
  </div>
980
  </div>
981
-
982
- </div>
983
  </div>
984
 
985
  <script>
986
  // Main Application Logic (Unchanged)
987
  (function() {
988
  // DOM Elements
989
- const formContainer = document.querySelector('#imageToVideoApp .control-panel');
990
  const imageFileInput = document.getElementById('imageFile');
991
  const imagePreview = document.getElementById('imagePreview');
992
  const imageDropZone = document.getElementById('image-drop-zone');
@@ -1002,12 +283,10 @@
1002
  const statusMessagesDiv = document.getElementById('statusMessages');
1003
  const aiLoader = document.getElementById('aiLoader');
1004
  const aiLoaderText = document.getElementById('aiLoaderText');
1005
- const progressBarContainer = document.getElementById('progressBarContainer');
1006
  const progressBar = document.getElementById('progressBar');
1007
  const outputSection = document.getElementById('outputSection');
1008
  const btnRestart = document.getElementById('btnRestart');
1009
  const btnDownloadVideo = document.getElementById('btnDownloadVideo');
1010
- const downloadLinkStatus = document.getElementById('downloadLinkStatus');
1011
 
1012
  // Constants
1013
  const VIDEO_SPACE_URL_BASE = "https://lightricks-ltx-video-distilled.hf.space/gradio_api";
@@ -1038,22 +317,17 @@
1038
  }
1039
 
1040
  function showCriticalError(message, isTranslationError = false) {
1041
- const titleElement = criticalErrorSection.querySelector('.error-header span');
1042
-
1043
  lastErrorWasGpuQuota = false;
1044
  const lowerCaseMessage = message.toLowerCase();
1045
 
1046
  if (lowerCaseMessage.includes("gpu") || lowerCaseMessage.includes("quota") || lowerCaseMessage.includes("exceeded") || lowerCaseMessage.includes("limit")) {
1047
- criticalErrorMessage.innerHTML = `<strong>راهنمای رفع محدودیت GPU</strong><p>برای رفع محدودیت:</p><ul><li>فیلترشکن را خاموش کنید</li><li>حالت هواپیما را فعال و غیرفعال کنید</li><li>دکمه تلاش مجدد را بزنید</li></ul>`;
1048
- if (titleElement) titleElement.textContent = 'محدودیت GPU';
1049
  lastErrorWasGpuQuota = true;
1050
  } else {
1051
  criticalErrorMessage.innerHTML = `<p>${message}</p>`;
1052
- if (titleElement) {
1053
- titleElement.textContent = isTranslationError ? 'خطای ترجمه' : 'خطای پردازش';
1054
- }
1055
  }
1056
-
 
1057
  criticalErrorSection.classList.add('active');
1058
  statusSection.classList.remove('active');
1059
  outputSection.classList.remove('active');
@@ -1075,6 +349,7 @@
1075
  }
1076
  if (type === 'error' && !isPersistent) isPersistent = true;
1077
 
 
1078
  statusSection.classList.add('active');
1079
  const messageDiv = document.createElement('div');
1080
  messageDiv.className = `status-message ${type}`;
@@ -1089,7 +364,6 @@
1089
 
1090
  statusMessagesDiv.insertBefore(messageDiv, statusMessagesDiv.firstChild);
1091
  statusMessagesDiv.scrollTop = 0;
1092
-
1093
  }
1094
 
1095
  function clearStatusMessages() {
@@ -1102,7 +376,6 @@
1102
  }
1103
  outputVideo.src = '';
1104
  finalSeedElement.textContent = '';
1105
- downloadLinkStatus.textContent = '';
1106
  btnDownloadVideo.style.display = 'none';
1107
  }
1108
 
@@ -1121,8 +394,8 @@
1121
  }
1122
 
1123
  function initializeForm() {
1124
- formContainer.style.opacity = '1';
1125
  hideCriticalError();
 
1126
  statusSection.classList.remove('active');
1127
  outputSection.classList.remove('active');
1128
  clearStatusMessages();
@@ -1153,7 +426,7 @@
1153
  };
1154
 
1155
  if (aiLoader.style.display !== 'none') {
1156
- setAiLoaderText("در حال ترجمه پرامپت شما...");
1157
  }
1158
 
1159
  try {
@@ -1162,7 +435,7 @@
1162
  headers: { 'Content-Type': 'application/json' },
1163
  body: JSON.stringify(payload)
1164
  });
1165
- if (!joinResponse.ok) throw new Error(`خطای اتصال به صف مترجم: ${joinResponse.status}`);
1166
  const joinData = await joinResponse.json();
1167
  if (!joinData.event_id) throw new Error("پاسخ نامعتبر از سرور مترجم.");
1168
 
@@ -1281,7 +554,6 @@
1281
  outputSection.classList.add('active');
1282
  outputVideo.src = ltxVideoUrl;
1283
  outputVideo.load();
1284
- outputVideo.scrollIntoView({ behavior: 'smooth', block: 'center' });
1285
  finalSeedElement.textContent = data.output.data[1] ? `Seed: ${data.output.data[1]}` : '';
1286
  prepareCustomDownloadLink(ltxVideoUrl);
1287
  }, 300);
@@ -1303,7 +575,6 @@
1303
  }
1304
 
1305
  async function prepareCustomDownloadLink(ltxVideoUrl) {
1306
- downloadLinkStatus.textContent = 'آماده‌سازی لینک دانلود...';
1307
  btnDownloadVideo.style.display = 'none';
1308
  btnDownloadVideo.onclick = null;
1309
  try {
@@ -1320,7 +591,6 @@
1320
  }
1321
  const uploadData = await uploadResponse.json();
1322
  if (uploadData.success && uploadData.url) {
1323
- downloadLinkStatus.textContent = '';
1324
  btnDownloadVideo.style.display = 'flex';
1325
  btnDownloadVideo.onclick = () => window.open(uploadData.url, '_blank');
1326
  } else {
@@ -1328,15 +598,13 @@
1328
  }
1329
  } catch (error) {
1330
  console.error("خطا در تهیه لینک دانلود:", error);
1331
- downloadLinkStatus.textContent = `خطا در ساخت لینک دانلود.`;
1332
- btnDownloadVideo.style.display = 'none';
1333
  }
1334
  }
1335
 
1336
  // Event Listeners
1337
  document.addEventListener('DOMContentLoaded', initializeForm);
1338
 
1339
- // *** FIX: UPLOAD FUNCTIONALITY ***
1340
  imageDropZone.addEventListener('click', () => imageFileInput.click());
1341
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
1342
  imageDropZone.addEventListener(eventName, e => {
@@ -1364,15 +632,8 @@
1364
  }
1365
  });
1366
 
1367
- btnRestart.addEventListener('click', () => {
1368
- outputSection.classList.remove('active');
1369
- hideCriticalError();
1370
- initializeForm();
1371
- });
1372
-
1373
- btnCriticalErrorGoBack.addEventListener('click', () => {
1374
- hideCriticalError();
1375
- });
1376
 
1377
  btnCriticalErrorRetry.addEventListener('click', async () => {
1378
  if (lastAttemptedVideoPayload) {
@@ -1480,12 +741,11 @@
1480
  clearStatusMessages();
1481
  hideCriticalError();
1482
  generateButton.disabled = true;
1483
-
1484
  statusSection.classList.add('active');
1485
  aiLoader.style.display = 'flex';
1486
  outputSection.classList.remove('active');
1487
 
1488
- // Calculate dimensions
1489
  const [ratioW_str, ratioH_str] = autoSelectedAspectRatio.split(':');
1490
  const ratioW = parseFloat(ratioW_str);
1491
  const ratioH = parseFloat(ratioH_str);
@@ -1529,87 +789,22 @@
1529
  </script>
1530
 
1531
  <script>
1532
- // Enhanced Header Animation Script
1533
  document.addEventListener('DOMContentLoaded', () => {
1534
  const canvas = document.getElementById('neural-network-canvas');
1535
- if (!canvas) return;
1536
  const header = canvas.parentElement;
1537
  const ctx = canvas.getContext('2d');
1538
  let particles = [];
1539
- const particleCount = 25;
1540
- const maxDistance = 120;
1541
  const computedStyles = getComputedStyle(document.documentElement);
1542
- const particleColor = '#4A6CFA';
1543
- const lineColor = '#667eea';
1544
-
1545
- function resizeCanvas() {
1546
- canvas.width = header.clientWidth;
1547
- canvas.height = header.clientHeight;
1548
- init();
1549
- }
1550
-
1551
- class Particle {
1552
- constructor() {
1553
- this.x = Math.random() * canvas.width;
1554
- this.y = Math.random() * canvas.height;
1555
- this.vx = (Math.random() - 0.5) * 0.4;
1556
- this.vy = (Math.random() - 0.5) * 0.4;
1557
- this.radius = Math.random() * 2 + 1;
1558
- this.opacity = Math.random() * 0.6 + 0.4;
1559
- }
1560
- update() {
1561
- this.x += this.vx;
1562
- this.y += this.vy;
1563
- if (this.x < 0 || this.x > canvas.width) this.vx *= -1;
1564
- if (this.y < 0 || this.y > canvas.height) this.vy *= -1;
1565
- }
1566
- draw() {
1567
- ctx.beginPath();
1568
- ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
1569
- ctx.fillStyle = `rgba(74, 108, 250, ${this.opacity})`;
1570
- ctx.fill();
1571
- }
1572
- }
1573
-
1574
- function init() {
1575
- particles = [];
1576
- for (let i = 0; i < particleCount; i++) {
1577
- particles.push(new Particle());
1578
- }
1579
- }
1580
-
1581
- function connectParticles() {
1582
- for (let i = 0; i < particles.length; i++) {
1583
- for (let j = i + 1; j < particles.length; j++) {
1584
- const dx = particles[i].x - particles[j].x;
1585
- const dy = particles[i].y - particles[j].y;
1586
- const distance = Math.sqrt(dx * dx + dy * dy);
1587
- if (distance < maxDistance) {
1588
- ctx.beginPath();
1589
- ctx.moveTo(particles[i].x, particles[i].y);
1590
- ctx.lineTo(particles[j].x, particles[j].y);
1591
- const opacity = (1 - distance / maxDistance) * 0.3;
1592
- ctx.strokeStyle = `rgba(102, 126, 234, ${opacity})`;
1593
- ctx.lineWidth = 0.5;
1594
- ctx.stroke();
1595
- }
1596
- }
1597
- }
1598
- }
1599
-
1600
- function animate() {
1601
- ctx.clearRect(0, 0, canvas.width, canvas.height);
1602
- particles.forEach(particle => {
1603
- particle.update();
1604
- particle.draw();
1605
- });
1606
- connectParticles();
1607
- requestAnimationFrame(animate);
1608
- }
1609
-
1610
- window.addEventListener('resize', resizeCanvas);
1611
- resizeCanvas();
1612
- animate();
1613
  });
1614
  </script>
1615
  </body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Video Studio ✨</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700;800&display=swap" rel="stylesheet">
 
 
 
 
 
8
  <style>
9
+ :root {
 
 
 
10
  --app-font: 'Vazirmatn', sans-serif;
11
+ --app-bg: #F8F9FC;
12
  --panel-bg: #FFFFFF;
13
+ --panel-border: #EAEFF7;
14
+ --input-bg: #F6F8FB;
15
+ --input-border: #E1E7EF;
16
  --text-primary: #1A202C;
17
+ --text-secondary: #626F86;
18
+ --text-tertiary: #8A94A6;
19
  --accent-primary: #4A6CFA;
20
  --accent-primary-hover: #3553D6;
21
  --accent-primary-glow: rgba(74, 108, 250, 0.25);
22
  --accent-secondary: #0FD4A8;
23
+ --success-color: #38A169;
24
  --danger-color: #e53e3e;
25
  --danger-color-hover: #c53030;
26
+ --shadow-sm: 0 1px 2px 0 rgba(26, 32, 44, 0.03);
27
+ --shadow-md: 0 4px 6px -1px rgba(26, 32, 44, 0.05), 0 2px 4px -2px rgba(26, 32, 44, 0.04);
28
+ --shadow-lg: 0 10px 15px -3px rgba(26, 32, 44, 0.06), 0 4px 6px -4px rgba(26, 32, 44, 0.05);
29
+ --shadow-xl: 0 20px 25px -5px rgba(26, 32, 44, 0.07), 0 8px 10px -6px rgba(26, 32, 44, 0.05);
30
+ --radius-card: 24px;
31
+ --radius-btn: 14px;
32
+ --radius-input: 12px;
33
+ --transition-smooth: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
37
+ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
 
 
 
38
 
39
  body {
40
+ font-family: var(--app-font);
41
+ background-color: var(--app-bg);
42
+ color: var(--text-primary);
43
  margin: 0;
44
+ padding: 2.5rem 1rem;
45
+ display: flex;
46
+ justify-content: center;
47
+ align-items: flex-start;
48
+ min-height: 100vh;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
+ .container { max-width: 820px; width: 100%; }
51
 
52
+ header {
 
53
  position: relative;
54
  text-align: center;
55
+ margin-bottom: 2.5rem;
56
+ padding: 2rem 0;
57
  animation: fadeIn 0.8s 0.1s ease-out backwards;
58
  overflow: hidden;
 
 
 
 
 
 
 
59
  }
 
60
  #neural-network-canvas {
61
  position: absolute;
62
  top: 0;
 
64
  width: 100%;
65
  height: 100%;
66
  z-index: 1;
 
67
  }
68
+ h1, .subtitle {
 
 
69
  position: relative;
70
  z-index: 2;
71
  }
 
 
 
 
 
 
 
 
72
 
73
+ h1 {
74
+ font-size: 2.8rem;
75
+ font-weight: 800;
76
+ margin: 0 0 0.8rem 0;
77
+ background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
 
 
 
 
 
 
 
 
 
 
 
78
  -webkit-background-clip: text;
79
  -webkit-text-fill-color: transparent;
80
+ letter-spacing: -1px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  }
82
+ .subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-top: 0; }
83
 
84
+ main {
 
 
 
 
 
85
  padding: 3rem;
86
+ background-color: var(--panel-bg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  border-radius: var(--radius-card);
88
+ box-shadow: var(--shadow-xl);
89
+ border: 1px solid var(--panel-border);
90
+ animation: fadeIn 0.8s 0.3s ease-out backwards;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
 
93
+ .form-group { margin-bottom: 2.5rem; }
94
+ .form-group:last-child { margin-bottom: 0; }
95
+
96
+ .form-label {
 
 
 
 
97
  display: flex;
98
  align-items: center;
99
+ gap: 0.75rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  font-weight: 700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  color: var(--text-primary);
102
+ font-size: 1.2em;
103
+ margin-bottom: 1.2rem;
104
+ }
105
+ .form-label svg { width: 24px; height: 24px; color: var(--accent-primary); }
106
+
107
+ #image-drop-zone {
108
+ position: relative; border: 2px dashed var(--input-border); border-radius: var(--radius-input); padding: 2.5rem; text-align: center;
109
+ cursor: pointer; transition: var(--transition-smooth); background-color: var(--input-bg); min-height: 200px; display: flex;
110
+ flex-direction: column; justify-content: center; align-items: center; overflow: hidden;
111
+ }
112
+ #image-drop-zone.drag-over, #image-drop-zone:hover:not(.has-image) { border-color: var(--accent-primary); background-color: #fff; box-shadow: 0 0 15px var(--accent-primary-glow); }
113
+ #image-drop-zone.has-image { border-style: solid; border-color: var(--success-color); padding: 0; cursor: default; }
114
+ .upload-content { display: flex; flex-direction: column; align-items: center; gap: 1rem; }
115
+ .upload-icon svg { width: 48px; height: 48px; color: var(--accent-primary); stroke-width: 1.5; opacity: 0.8; }
116
+ #image-drop-zone p { margin: 0; color: var(--text-secondary); font-weight: 500; }
117
+ #imagePreview { display: none; width: 100%; height: 100%; object-fit: contain; position: absolute; top: 0; left: 0; }
118
+ #image-drop-zone.has-image .upload-content { display: none; }
119
+ #image-drop-zone.has-image #imagePreview { display: block; }
120
+
121
+ textarea { width: 100%; padding: 1rem 1.2rem; border-radius: var(--radius-input); border: 1px solid var(--input-border); background-color: var(--input-bg); color: var(--text-primary); box-shadow: var(--shadow-sm) inset; font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: var(--transition-smooth); min-height: 120px; resize: vertical; }
122
+ textarea:focus { outline: none; border-color: var(--accent-primary); box-shadow: 0 0 0 3px var(--accent-primary-glow), var(--shadow-sm) inset; background-color: var(--panel-bg); }
123
+
124
+ #generateButton {
125
+ display: flex; align-items: center; justify-content: center; gap: 0.75rem; width: 100%; padding: 1.1rem;
126
+ font-size: 1.2rem; font-weight: 700; background: linear-gradient(95deg, var(--accent-secondary) 0%, var(--accent-primary) 100%);
127
+ color: #fff; border: none; border-radius: var(--radius-btn); cursor: pointer; transition: all 0.3s ease;
128
+ box-shadow: 0 6px 12px -3px var(--accent-primary-glow), 0 6px 12px -3px rgba(15, 212, 168, 0.25); margin-top: 1.5rem;
129
+ }
130
+ #generateButton svg { width: 24px; height: 24px; margin-left: 4px; filter: drop-shadow(0 0 5px rgba(255,255,255,0.5)); }
131
+ #generateButton:hover:not(:disabled) { transform: translateY(-5px) scale(1.02); box-shadow: 0 8px 20px -4px var(--accent-primary-glow), 0 8px 20px -4px rgba(15, 212, 168, 0.3); }
132
+ #generateButton:disabled { background: var(--text-tertiary); cursor: not-allowed; box-shadow: none; opacity: 0.7; }
133
+
134
+ /* Result Container & Children */
135
+ #result-container { min-height: 250px; position: relative; padding: 1rem; background-color: var(--input-bg); border-radius: var(--radius-card); border: 2px dashed var(--input-border); box-shadow: var(--shadow-sm) inset; transition: var(--transition-smooth); display: flex; flex-direction: column; align-items: center; justify-content: center; }
136
+ #result-container.active { border-style: solid; border-color: var(--panel-border); }
137
+
138
+ #statusSection, #outputSection, #criticalErrorSection { display: none; width: 100%; }
139
+ #statusSection.active, #outputSection.active, #criticalErrorSection.active { display: block; animation: fadeIn 0.5s; }
140
+
141
+ /* Progress Bar Styling */
142
+ .film-timeline { height: 8px; background: var(--panel-border); border-radius: 4px; overflow: hidden; margin: 1rem 0; }
143
+ #progressBar { height: 100%; background: linear-gradient(90deg, var(--accent-secondary), var(--accent-primary)); transition: width 0.4s ease; border-radius: 4px; }
144
+
145
+ /* Status Messages Styling */
146
+ #statusMessages { max-height: 150px; overflow-y: auto; width: 100%; padding: 0.5rem; }
147
+ .status-message {
148
+ display: flex; align-items: center; gap: 0.75rem; padding: 0.6rem 1rem;
149
+ margin-bottom: 0.5rem; border-radius: var(--radius-input); font-size: 0.9rem;
150
+ background: var(--panel-bg); border: 1px solid var(--panel-border); color: var(--text-secondary);
151
+ }
152
+ .status-message.success { border-left: 4px solid var(--success-color); color: var(--success-color); }
153
+ .status-message.error { border-left: 4px solid var(--danger-color); color: var(--danger-color); }
154
+ .status-icon { width: 18px; height: 18px; }
155
+
156
+ /* AI Loader Spinner */
157
+ #aiLoader { align-items: center; justify-content: center; padding: 2rem 0; }
158
+ #aiLoader .spinner { width: 32px; height: 32px; border: 4px solid var(--input-border); border-top-color: var(--accent-primary); border-radius: 50%; animation: spin 1s linear infinite; }
159
+ #aiLoaderText { margin-top: 1rem; color: var(--text-secondary); font-weight: 500; }
160
+
161
+ /* Video Output Styling */
162
+ #outputVideo { width: 100%; max-width: 500px; border-radius: var(--radius-input); margin: 1rem auto; display: block; background-color: #000; box-shadow: var(--shadow-md); }
163
+ #finalSeed { text-align: center; color: var(--text-tertiary); font-size: 0.85rem; margin-top: 1rem; }
164
+ .video-controls { display: flex; justify-content: center; gap: 1rem; margin-top: 1.5rem; }
165
+ .video-button {
166
+ padding: 0.7rem 1.5rem; border-radius: var(--radius-btn); border: none; cursor: pointer; font-family: var(--app-font);
167
+ font-weight: 600; font-size: 1rem; transition: var(--transition-smooth); display: flex; align-items: center; gap: 0.5rem;
168
+ }
169
+ .video-button.primary { background-color: var(--accent-primary); color: white; }
170
+ .video-button.primary:hover { background-color: var(--accent-primary-hover); transform: translateY(-2px); }
171
+ .video-button:not(.primary) { background-color: var(--input-bg); color: var(--text-secondary); border: 1px solid var(--input-border); }
172
+ .video-button:not(.primary):hover { background-color: var(--panel-border); color: var(--text-primary); }
173
+
174
+ /* Error Panel Styling */
175
+ #criticalErrorSection { text-align: center; padding: 1.5rem; }
176
+ #criticalErrorMessage { color: var(--danger-color); font-weight: 500; margin-bottom: 1.5rem; line-height: 1.6; }
177
 
 
 
 
 
 
 
178
 
 
179
  @media (max-width: 768px) {
180
+ main { padding: 1.5rem; } h1 { font-size: 2.2rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
  </style>
183
  </head>
184
  <body>
185
+ <div class="container">
186
+ <header>
187
+ <canvas id="neural-network-canvas"></canvas>
188
+ <h1>استودیو ویدیو هوش مصنوعی ✨</h1>
189
+ <p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی به ویدیو سینمایی تبدیل کنید</p>
190
+ </header>
191
+
192
+ <main>
193
+ <div class="form-group">
194
+ <div class="form-label">
195
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4Z"/></svg>
196
+ ۱. تصویر خود را انتخاب کنید
197
+ </div>
198
+ <div id="image-drop-zone">
199
+ <div class="upload-content">
200
+ <div class="upload-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg></div>
201
+ <p>فایل تصویر را اینجا بکشید یا برای انتخاب کلیک کنید</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  </div>
203
+ <img id="imagePreview" src="" alt="Preview">
204
  </div>
205
+ <input type="file" id="imageFile" accept="image/jpeg, image/png, image/webp" hidden>
206
+ </div>
207
+
208
+ <div class="form-group">
209
+ <label for="prompt" class="form-label">
210
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
211
+ ۲. دستور ساخت ویدیو را بنویسید
212
+ </label>
213
+ <textarea id="prompt" rows="4" placeholder="مثال: زوم آهسته به بیرون در حالی که برگ‌ها در باد می‌رقصند و نور خورشید از بین درختان می‌تابد"></textarea>
214
+ <button id="generateButton">
215
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3L12 8L17 10L12 12L10 17L8 12L3 10L8 8L10 3z"/></svg>
216
+ <span>ساخت ویدیو جادویی</span>
217
+ </button>
218
+ </div>
219
 
220
+ <div class="form-group">
221
+ <div class="form-label">
222
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 3L12 8L17 10L12 12L10 17L8 12L3 10L8 8L10 3z"/><path d="M21 14l-1.5 3-3-1.5 3-3 1.5 3z"/><path d="M19.5 2.5l-3 1.5 1.5 3 3-1.5-1.5-3z"/></svg>
223
+ ۳. نتیجه را ببینید
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  </div>
225
+ <div id="result-container">
226
 
227
+ <div id="statusSection">
228
+ <div id="statusMessages"></div>
229
+ <div class="film-timeline">
230
+ <div id="progressBar" style="width: 0%"></div>
231
+ </div>
232
+ <div id="aiLoader" style="display: none;">
233
+ <div class="spinner"></div>
234
+ <div id="aiLoaderText">هوش مصنوعی در حال ساخت شاهکار شما...</div>
235
+ </div>
236
  </div>
 
 
 
 
 
 
237
 
238
+ <div id="outputSection">
239
+ <video id="outputVideo" controls preload="metadata" playsinline></video>
240
+ <p id="finalSeed"></p>
241
+ <div class="video-controls">
242
+ <button id="btnDownloadVideo" class="video-button primary" style="display: none;">
243
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
244
+ دانلود شاهکار
245
+ </button>
246
+ <button id="btnRestart" class="video-button">
247
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
248
+ ساخت ویدیو جدید
249
+ </button>
250
+ </div>
251
  </div>
252
 
253
+ <div id="criticalErrorSection">
254
+ <div id="criticalErrorMessage"></div>
255
+ <div class="video-controls">
256
+ <button id="btnCriticalErrorGoBack" class="video-button">بازگشت</button>
257
+ <button id="btnCriticalErrorRetry" class="video-button primary">تلاش مجدد</button>
258
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  </div>
262
  </div>
263
+ </main>
 
264
  </div>
265
 
266
  <script>
267
  // Main Application Logic (Unchanged)
268
  (function() {
269
  // DOM Elements
270
+ const resultContainer = document.getElementById('result-container');
271
  const imageFileInput = document.getElementById('imageFile');
272
  const imagePreview = document.getElementById('imagePreview');
273
  const imageDropZone = document.getElementById('image-drop-zone');
 
283
  const statusMessagesDiv = document.getElementById('statusMessages');
284
  const aiLoader = document.getElementById('aiLoader');
285
  const aiLoaderText = document.getElementById('aiLoaderText');
 
286
  const progressBar = document.getElementById('progressBar');
287
  const outputSection = document.getElementById('outputSection');
288
  const btnRestart = document.getElementById('btnRestart');
289
  const btnDownloadVideo = document.getElementById('btnDownloadVideo');
 
290
 
291
  // Constants
292
  const VIDEO_SPACE_URL_BASE = "https://lightricks-ltx-video-distilled.hf.space/gradio_api";
 
317
  }
318
 
319
  function showCriticalError(message, isTranslationError = false) {
 
 
320
  lastErrorWasGpuQuota = false;
321
  const lowerCaseMessage = message.toLowerCase();
322
 
323
  if (lowerCaseMessage.includes("gpu") || lowerCaseMessage.includes("quota") || lowerCaseMessage.includes("exceeded") || lowerCaseMessage.includes("limit")) {
324
+ criticalErrorMessage.innerHTML = `<strong>ظرفیت سرور تکمیل است.</strong><p>برای رفع مشکل، فیلترشکن را خاموش و روشن کرده و دوباره تلاش کنید.</p>`;
 
325
  lastErrorWasGpuQuota = true;
326
  } else {
327
  criticalErrorMessage.innerHTML = `<p>${message}</p>`;
 
 
 
328
  }
329
+
330
+ resultContainer.classList.add('active');
331
  criticalErrorSection.classList.add('active');
332
  statusSection.classList.remove('active');
333
  outputSection.classList.remove('active');
 
349
  }
350
  if (type === 'error' && !isPersistent) isPersistent = true;
351
 
352
+ resultContainer.classList.add('active');
353
  statusSection.classList.add('active');
354
  const messageDiv = document.createElement('div');
355
  messageDiv.className = `status-message ${type}`;
 
364
 
365
  statusMessagesDiv.insertBefore(messageDiv, statusMessagesDiv.firstChild);
366
  statusMessagesDiv.scrollTop = 0;
 
367
  }
368
 
369
  function clearStatusMessages() {
 
376
  }
377
  outputVideo.src = '';
378
  finalSeedElement.textContent = '';
 
379
  btnDownloadVideo.style.display = 'none';
380
  }
381
 
 
394
  }
395
 
396
  function initializeForm() {
 
397
  hideCriticalError();
398
+ resultContainer.classList.remove('active');
399
  statusSection.classList.remove('active');
400
  outputSection.classList.remove('active');
401
  clearStatusMessages();
 
426
  };
427
 
428
  if (aiLoader.style.display !== 'none') {
429
+ setAiLoaderText("در حال ترجمه دستور شما...");
430
  }
431
 
432
  try {
 
435
  headers: { 'Content-Type': 'application/json' },
436
  body: JSON.stringify(payload)
437
  });
438
+ if (!joinResponse.ok) throw new Error(`خطای اتصال به سرور مترجم: ${joinResponse.status}`);
439
  const joinData = await joinResponse.json();
440
  if (!joinData.event_id) throw new Error("پاسخ نامعتبر از سرور مترجم.");
441
 
 
554
  outputSection.classList.add('active');
555
  outputVideo.src = ltxVideoUrl;
556
  outputVideo.load();
 
557
  finalSeedElement.textContent = data.output.data[1] ? `Seed: ${data.output.data[1]}` : '';
558
  prepareCustomDownloadLink(ltxVideoUrl);
559
  }, 300);
 
575
  }
576
 
577
  async function prepareCustomDownloadLink(ltxVideoUrl) {
 
578
  btnDownloadVideo.style.display = 'none';
579
  btnDownloadVideo.onclick = null;
580
  try {
 
591
  }
592
  const uploadData = await uploadResponse.json();
593
  if (uploadData.success && uploadData.url) {
 
594
  btnDownloadVideo.style.display = 'flex';
595
  btnDownloadVideo.onclick = () => window.open(uploadData.url, '_blank');
596
  } else {
 
598
  }
599
  } catch (error) {
600
  console.error("خطا در تهیه لینک دانلود:", error);
601
+ addStatusMessage('خطا در ساخت لینک دانلود.', 'error');
 
602
  }
603
  }
604
 
605
  // Event Listeners
606
  document.addEventListener('DOMContentLoaded', initializeForm);
607
 
 
608
  imageDropZone.addEventListener('click', () => imageFileInput.click());
609
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
610
  imageDropZone.addEventListener(eventName, e => {
 
632
  }
633
  });
634
 
635
+ btnRestart.addEventListener('click', initializeForm);
636
+ btnCriticalErrorGoBack.addEventListener('click', hideCriticalError);
 
 
 
 
 
 
 
637
 
638
  btnCriticalErrorRetry.addEventListener('click', async () => {
639
  if (lastAttemptedVideoPayload) {
 
741
  clearStatusMessages();
742
  hideCriticalError();
743
  generateButton.disabled = true;
744
+ resultContainer.classList.add('active');
745
  statusSection.classList.add('active');
746
  aiLoader.style.display = 'flex';
747
  outputSection.classList.remove('active');
748
 
 
749
  const [ratioW_str, ratioH_str] = autoSelectedAspectRatio.split(':');
750
  const ratioW = parseFloat(ratioW_str);
751
  const ratioH = parseFloat(ratioH_str);
 
789
  </script>
790
 
791
  <script>
792
+ // --- Header Animation Script (From Photoshop Template) ---
793
  document.addEventListener('DOMContentLoaded', () => {
794
  const canvas = document.getElementById('neural-network-canvas');
 
795
  const header = canvas.parentElement;
796
  const ctx = canvas.getContext('2d');
797
  let particles = [];
798
+ const particleCount = 20; const maxDistance = 100;
 
799
  const computedStyles = getComputedStyle(document.documentElement);
800
+ const particleColor = computedStyles.getPropertyValue('--accent-primary').trim();
801
+ const lineColor = computedStyles.getPropertyValue('--text-tertiary').trim();
802
+ function resizeCanvas() { canvas.width = header.clientWidth; canvas.height = header.clientHeight; init(); }
803
+ class Particle { constructor() { this.x = Math.random() * canvas.width; this.y = Math.random() * canvas.height; this.vx = (Math.random() - 0.5) * 0.3; this.vy = (Math.random() - 0.5) * 0.3; this.radius = 1.2; } update() { this.x += this.vx; this.y += this.vy; if (this.x < 0 || this.x > canvas.width) this.vx *= -1; if (this.y < 0 || this.y > canvas.height) this.vy *= -1; } draw() { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fillStyle = particleColor; ctx.fill(); } }
804
+ function init() { particles = []; for (let i = 0; i < particleCount; i++) { particles.push(new Particle()); } }
805
+ function connectParticles() { for (let i = 0; i < particles.length; i++) { for (let j = i + 1; j < particles.length; j++) { const dx = particles[i].x - particles[j].x; const dy = particles[i].y - particles[j].y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < maxDistance) { ctx.beginPath(); ctx.moveTo(particles[i].x, particles[i].y); ctx.lineTo(particles[j].x, particles[j].y); ctx.strokeStyle = lineColor; ctx.lineWidth = 0.2; ctx.globalAlpha = 1 - distance / maxDistance; ctx.stroke(); } } } ctx.globalAlpha = 1; }
806
+ function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); particles.forEach(particle => { particle.update(); particle.draw(); }); connectParticles(); requestAnimationFrame(animate); }
807
+ window.addEventListener('resize', resizeCanvas); resizeCanvas(); animate();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
808
  });
809
  </script>
810
  </body>