akhaliq HF Staff commited on
Commit
97ddbe3
Β·
1 Parent(s): 5a6c23f

Implement collapsible sidebar deck and integrate official Resemble.AI mint-teal branding colors

Browse files
Files changed (1) hide show
  1. index.html +603 -490
index.html CHANGED
@@ -7,7 +7,7 @@
7
 
8
  <!-- Meta tags for premium look and SEO -->
9
  <meta name="description" content="Generate highly expressive speech with voice cloning. Powered by LTX-2.3 and Resemble Perth watermarking.">
10
- <meta name="theme-color" content="#0a0b10">
11
 
12
  <!-- Google Fonts: Outfit and Inter -->
13
  <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -16,22 +16,21 @@
16
 
17
  <style>
18
  :root {
19
- --bg-color: #06070a;
20
- --panel-bg: rgba(13, 15, 24, 0.7);
21
- --panel-border: rgba(255, 255, 255, 0.05);
 
22
  --text-primary: #f8fafc;
23
  --text-secondary: #94a3b8;
24
- --accent-orange: #ff6b35;
25
- --accent-orange-hover: #ff8554;
26
- --accent-orange-glow: rgba(255, 107, 53, 0.25);
27
- --accent-purple: #8b5cf6;
28
- --accent-purple-hover: #a78bfa;
29
- --accent-purple-glow: rgba(139, 92, 246, 0.2);
30
  --accent-green: #10b981;
31
- --radius-lg: 20px;
32
  --radius-md: 12px;
33
  --radius-sm: 8px;
34
- --transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
35
  }
36
 
37
  * {
@@ -46,46 +45,149 @@
46
  font-family: 'Inter', sans-serif;
47
  min-height: 100vh;
48
  line-height: 1.5;
49
- overflow-x: hidden;
50
  position: relative;
51
- display: flex;
52
- flex-direction: column;
53
  }
54
 
55
- /* Modern background radial glows */
56
  body::before {
57
  content: '';
58
  position: absolute;
59
  top: -10%;
60
- left: 5%;
61
- width: 50%;
62
- height: 50%;
63
- background: radial-gradient(circle, var(--accent-orange-glow) 0%, transparent 60%);
64
  z-index: -1;
65
  filter: blur(80px);
66
  pointer-events: none;
67
- opacity: 0.8;
68
  }
69
 
70
  body::after {
71
  content: '';
72
  position: absolute;
73
- bottom: 5%;
74
  right: 5%;
75
- width: 45%;
76
- height: 45%;
77
- background: radial-gradient(circle, var(--accent-purple-glow) 0%, transparent 60%);
78
  z-index: -1;
79
  filter: blur(80px);
80
  pointer-events: none;
81
- opacity: 0.6;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
83
 
84
- .container {
 
85
  width: 100%;
86
- max-width: 1200px;
87
  margin: 0 auto;
88
- padding: 20px;
89
  display: flex;
90
  flex-direction: column;
91
  gap: 24px;
@@ -98,6 +200,7 @@
98
  text-align: center;
99
  padding: 20px 0 10px 0;
100
  gap: 12px;
 
101
  }
102
 
103
  .logo-area {
@@ -118,38 +221,49 @@
118
 
119
  h1 {
120
  font-family: 'Outfit', sans-serif;
121
- font-size: 2.5rem;
122
  font-weight: 800;
123
- background: linear-gradient(135deg, #ffffff 40%, #ffa580 80%, #cfa0f7 100%);
124
  -webkit-background-clip: text;
125
  -webkit-text-fill-color: transparent;
126
  letter-spacing: -0.5px;
127
  }
128
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  .subtitle {
130
- font-size: 1rem;
131
  color: var(--text-secondary);
132
  font-weight: 400;
133
- max-width: 500px;
134
  }
135
 
136
  .ltx-banner {
137
- background: rgba(22, 28, 45, 0.4);
138
  border: 1px solid var(--panel-border);
139
- border-left: 3px solid var(--accent-orange);
140
  border-radius: var(--radius-md);
141
  padding: 12px 18px;
142
  color: #cbd5e1;
143
- font-size: 0.85rem;
144
- line-height: 1.6;
145
- max-width: 800px;
146
  text-align: left;
147
- backdrop-filter: blur(12px);
148
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
 
149
  }
150
 
151
  .ltx-banner a {
152
- color: #ff9a6c;
153
  font-weight: 600;
154
  text-decoration: none;
155
  transition: var(--transition);
@@ -160,76 +274,44 @@
160
  text-decoration: underline;
161
  }
162
 
163
- /* 2-Column Responsive Workspace */
164
- main {
165
- display: grid;
166
- grid-template-columns: 1.2fr 1fr;
167
- gap: 24px;
168
- align-items: start;
169
- }
170
-
171
- @media (max-width: 960px) {
172
- main {
173
- grid-template-columns: 1fr;
174
- }
175
- h1 {
176
- font-size: 2rem;
177
- }
178
- .logo-emoji {
179
- font-size: 1.8rem;
180
- }
181
  }
182
 
183
- @media (max-width: 576px) {
184
- .container {
185
- padding: 12px;
186
- gap: 16px;
187
- }
188
- header {
189
- padding: 10px 0;
190
- }
191
- .ltx-banner {
192
- font-size: 0.8rem;
193
- padding: 10px 14px;
194
- }
195
  }
196
 
197
- .card {
 
198
  background: var(--panel-bg);
199
  border: 1px solid var(--panel-border);
200
  border-radius: var(--radius-lg);
201
  padding: 24px;
202
  backdrop-filter: blur(20px);
203
- box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);
204
  display: flex;
205
  flex-direction: column;
206
  gap: 20px;
207
  transition: var(--transition);
208
  }
209
 
210
- .card:hover {
211
- border-color: rgba(255, 255, 255, 0.08);
212
- }
213
-
214
- @media (max-width: 576px) {
215
- .card {
216
- padding: 18px;
217
- gap: 16px;
218
- }
219
- }
220
-
221
- .card-header {
222
- display: flex;
223
- align-items: center;
224
- gap: 10px;
225
- font-family: 'Outfit', sans-serif;
226
- font-size: 1.25rem;
227
- font-weight: 600;
228
- color: #ffffff;
229
- border-bottom: 1px solid rgba(255, 255, 255, 0.05);
230
- padding-bottom: 12px;
231
- }
232
-
233
  .form-group {
234
  display: flex;
235
  flex-direction: column;
@@ -237,8 +319,8 @@
237
  }
238
 
239
  .form-label {
240
- font-size: 0.8rem;
241
- font-weight: 600;
242
  text-transform: uppercase;
243
  letter-spacing: 0.8px;
244
  color: var(--text-secondary);
@@ -249,7 +331,7 @@
249
 
250
  .label-badge {
251
  font-size: 0.75rem;
252
- color: var(--accent-orange);
253
  text-transform: none;
254
  font-weight: 400;
255
  letter-spacing: 0;
@@ -257,61 +339,56 @@
257
 
258
  .textarea-custom {
259
  width: 100%;
260
- background: rgba(10, 11, 18, 0.7);
261
  border: 1px solid var(--panel-border);
262
  border-radius: var(--radius-md);
263
- padding: 14px 16px;
264
  color: var(--text-primary);
265
  font-family: 'Inter', sans-serif;
266
- font-size: 0.95rem;
267
- line-height: 1.5;
268
  resize: vertical;
269
- min-height: 120px;
270
  outline: none;
271
  transition: var(--transition);
272
  }
273
 
274
  .textarea-custom:focus {
275
- border-color: var(--accent-orange);
276
- box-shadow: 0 0 12px var(--accent-orange-glow);
277
- background: rgba(10, 11, 18, 0.9);
278
  }
279
 
280
- /* Modernized Flat Upload Block */
281
  .upload-zone {
282
- border: 2px dashed rgba(255, 255, 255, 0.1);
283
  border-radius: var(--radius-md);
284
- padding: 20px;
285
  text-align: center;
286
  cursor: pointer;
287
- background: rgba(255, 255, 255, 0.01);
288
  display: flex;
289
  flex-direction: column;
290
  align-items: center;
291
- gap: 8px;
292
  transition: var(--transition);
293
- min-height: 100px;
294
  justify-content: center;
295
  }
296
 
297
  .upload-zone:hover, .upload-zone.dragover {
298
- border-color: var(--accent-purple);
299
- background: rgba(139, 92, 246, 0.04);
300
  }
301
 
302
  .upload-icon {
303
- font-size: 1.8rem;
304
- color: var(--text-secondary);
305
  transition: var(--transition);
306
  }
307
 
308
- .upload-zone:hover .upload-icon {
309
- transform: translateY(-2px);
310
- color: var(--accent-purple);
311
- }
312
-
313
  .upload-text {
314
- font-size: 0.85rem;
315
  color: var(--text-secondary);
316
  }
317
 
@@ -320,17 +397,12 @@
320
  font-weight: 500;
321
  }
322
 
323
- .hidden-input {
324
- display: none;
325
- }
326
-
327
- /* Styled Uploaded Capsule */
328
  .file-capsule {
329
  display: flex;
330
  align-items: center;
331
  justify-content: space-between;
332
- background: rgba(139, 92, 246, 0.08);
333
- border: 1px solid rgba(139, 92, 246, 0.2);
334
  padding: 10px 14px;
335
  border-radius: var(--radius-md);
336
  width: 100%;
@@ -340,7 +412,7 @@
340
  display: flex;
341
  align-items: center;
342
  gap: 10px;
343
- font-size: 0.85rem;
344
  font-weight: 500;
345
  overflow: hidden;
346
  white-space: nowrap;
@@ -351,7 +423,7 @@
351
  background: none;
352
  border: none;
353
  color: var(--text-secondary);
354
- font-size: 1rem;
355
  cursor: pointer;
356
  transition: var(--transition);
357
  padding: 2px;
@@ -365,55 +437,27 @@
365
  transform: scale(1.1);
366
  }
367
 
368
- /* Modern Slider Accoridon Panels */
369
- .settings-accordion {
370
- background: rgba(255, 255, 255, 0.01);
371
- border: 1px solid var(--panel-border);
372
- border-radius: var(--radius-md);
373
- overflow: hidden;
374
- }
375
-
376
- .accordion-header {
377
- background: none;
378
- border: none;
379
- padding: 14px 18px;
380
- color: #ffffff;
381
- font-weight: 600;
382
- font-size: 0.9rem;
383
- width: 100%;
384
- display: flex;
385
- justify-content: space-between;
386
- align-items: center;
387
- cursor: pointer;
388
- outline: none;
389
- transition: var(--transition);
390
- }
391
-
392
- .accordion-header:hover {
393
- background: rgba(255, 255, 255, 0.03);
394
- }
395
-
396
- .accordion-icon {
397
- font-size: 0.75rem;
398
- transition: var(--transition);
399
- color: var(--text-secondary);
400
- }
401
-
402
- .accordion-body {
403
- max-height: 0;
404
- overflow: hidden;
405
- transition: max-height 0.3s ease-out;
406
- padding: 0 18px;
407
  display: flex;
408
  flex-direction: column;
409
  gap: 16px;
 
 
 
 
410
  }
411
 
412
- .accordion-body.open {
413
- max-height: 520px;
414
- padding-bottom: 20px;
415
- border-top: 1px solid rgba(255, 255, 255, 0.03);
416
- padding-top: 16px;
 
 
 
 
 
417
  }
418
 
419
  .slider-group {
@@ -431,18 +475,17 @@
431
  }
432
 
433
  .slider-value {
434
- color: #ffffff;
435
  font-weight: 700;
436
  font-family: monospace;
437
  }
438
 
439
- /* Custom Slider Tracks */
440
  input[type="range"] {
441
  -webkit-appearance: none;
442
  width: 100%;
443
- height: 5px;
444
  background: rgba(255, 255, 255, 0.06);
445
- border-radius: 3px;
446
  outline: none;
447
  cursor: pointer;
448
  }
@@ -452,8 +495,8 @@
452
  width: 14px;
453
  height: 14px;
454
  border-radius: 50%;
455
- background: var(--accent-orange);
456
- box-shadow: 0 0 8px var(--accent-orange-glow);
457
  transition: var(--transition);
458
  }
459
 
@@ -462,7 +505,7 @@
462
  background: #ffffff;
463
  }
464
 
465
- /* Seed Controls */
466
  .seed-row {
467
  display: flex;
468
  gap: 8px;
@@ -471,51 +514,51 @@
471
 
472
  .input-seed {
473
  flex: 1;
474
- background: rgba(10, 11, 18, 0.7);
475
- border: 1px solid var(--panel-border);
476
  border-radius: var(--radius-sm);
477
- padding: 10px 14px;
478
  color: var(--text-primary);
479
  font-family: monospace;
480
  outline: none;
481
- font-size: 0.9rem;
482
  transition: var(--transition);
483
- height: 40px;
484
  }
485
 
486
  .input-seed:focus {
487
- border-color: var(--accent-orange);
488
  }
489
 
490
  .btn-seed-random {
491
  background: rgba(255, 255, 255, 0.03);
492
- border: 1px solid var(--panel-border);
493
  border-radius: var(--radius-sm);
494
  color: var(--text-primary);
495
- height: 40px;
496
- width: 40px;
497
  display: flex;
498
  align-items: center;
499
  justify-content: center;
500
  cursor: pointer;
501
  transition: var(--transition);
502
- font-size: 0.95rem;
503
  }
504
 
505
  .btn-seed-random:hover {
506
- background: rgba(255, 255, 255, 0.08);
507
- border-color: rgba(255, 255, 255, 0.15);
508
  }
509
 
510
- /* Premium Floating Generate Button */
511
  .btn-generate {
512
- background: linear-gradient(135deg, var(--accent-orange) 0%, #ff8e53 100%);
513
  border: none;
514
  border-radius: var(--radius-md);
515
- color: #ffffff;
516
  font-family: 'Outfit', sans-serif;
517
  font-size: 1.05rem;
518
- font-weight: 700;
519
  padding: 14px;
520
  cursor: pointer;
521
  transition: var(--transition);
@@ -523,13 +566,15 @@
523
  align-items: center;
524
  justify-content: center;
525
  gap: 10px;
526
- box-shadow: 0 6px 20px rgba(255, 107, 53, 0.2);
527
  min-height: 48px;
 
528
  }
529
 
530
  .btn-generate:hover:not(:disabled) {
531
  transform: translateY(-1.5px);
532
- box-shadow: 0 10px 25px rgba(255, 107, 53, 0.35);
 
533
  }
534
 
535
  .btn-generate:active:not(:disabled) {
@@ -537,15 +582,15 @@
537
  }
538
 
539
  .btn-generate:disabled {
540
- background: #1b1c26;
541
- color: #4e526a;
542
  cursor: not-allowed;
543
  box-shadow: none;
544
  }
545
 
546
- /* Right Panel: Output & Controls */
547
  .output-wrapper {
548
- background: rgba(10, 11, 18, 0.5);
549
  border: 1px solid var(--panel-border);
550
  border-radius: var(--radius-md);
551
  padding: 20px;
@@ -553,7 +598,7 @@
553
  flex-direction: column;
554
  align-items: center;
555
  justify-content: center;
556
- min-height: 160px;
557
  position: relative;
558
  }
559
 
@@ -569,13 +614,14 @@
569
  .empty-icon {
570
  font-size: 2.2rem;
571
  opacity: 0.4;
 
572
  }
573
 
574
  .empty-text {
575
  font-size: 0.85rem;
576
  }
577
 
578
- /* Highly Responsive Audio Player Layout */
579
  .audio-player {
580
  width: 100%;
581
  display: flex;
@@ -585,13 +631,13 @@
585
 
586
  .visualizer-box {
587
  width: 100%;
588
- height: 50px;
589
- background: linear-gradient(90deg, rgba(139, 92, 246, 0.04) 0%, rgba(255, 107, 53, 0.04) 100%);
590
  border-radius: var(--radius-sm);
591
  display: flex;
592
  align-items: center;
593
  justify-content: center;
594
- border: 1px solid rgba(255, 255, 255, 0.02);
595
  overflow: hidden;
596
  }
597
 
@@ -604,8 +650,8 @@
604
 
605
  .wave-bar {
606
  width: 3px;
607
- height: 6px;
608
- background: var(--accent-purple);
609
  border-radius: 1px;
610
  transition: var(--transition);
611
  }
@@ -615,14 +661,14 @@
615
  }
616
 
617
  @keyframes playWave {
618
- 0% { height: 6px; }
619
- 100% { height: 32px; }
620
  }
621
 
622
- .wave-bar:nth-child(2n) { background: var(--accent-orange); animation-delay: 0.15s; }
623
  .wave-bar:nth-child(3n) { animation-delay: 0.3s; }
624
  .wave-bar:nth-child(4n) { animation-delay: 0.45s; }
625
- .wave-bar:nth-child(5n) { background: var(--accent-purple); animation-delay: 0.6s; }
626
 
627
  .player-row {
628
  display: flex;
@@ -661,12 +707,18 @@
661
  }
662
 
663
  .time-lbl {
664
- font-size: 0.75rem;
665
  color: var(--text-secondary);
666
  font-family: monospace;
667
  min-width: 32px;
668
  }
669
 
 
 
 
 
 
 
670
  .deck-footer {
671
  display: flex;
672
  align-items: center;
@@ -682,15 +734,19 @@
682
  display: flex;
683
  align-items: center;
684
  gap: 6px;
685
- max-width: 100px;
686
  flex-shrink: 0;
687
  }
688
 
689
  .vol-icon {
690
- font-size: 0.85rem;
691
  color: var(--text-secondary);
692
  }
693
 
 
 
 
 
694
  .speed-deck {
695
  display: flex;
696
  align-items: center;
@@ -699,10 +755,10 @@
699
 
700
  .btn-speed {
701
  background: rgba(255, 255, 255, 0.02);
702
- border: 1px solid var(--panel-border);
703
  border-radius: 6px;
704
  color: var(--text-secondary);
705
- font-size: 0.7rem;
706
  font-weight: 600;
707
  padding: 3px 6px;
708
  cursor: pointer;
@@ -710,9 +766,9 @@
710
  }
711
 
712
  .btn-speed.active, .btn-speed:hover {
713
- background: rgba(255, 255, 255, 0.08);
714
- color: #ffffff;
715
- border-color: rgba(255, 255, 255, 0.2);
716
  }
717
 
718
  .btn-download-wav {
@@ -720,7 +776,7 @@
720
  border: 1px solid var(--panel-border);
721
  border-radius: var(--radius-sm);
722
  color: #ffffff;
723
- font-size: 0.8rem;
724
  font-weight: 600;
725
  padding: 6px 12px;
726
  text-decoration: none;
@@ -731,8 +787,9 @@
731
  }
732
 
733
  .btn-download-wav:hover {
734
- background: #ffffff;
735
- color: var(--bg-color);
 
736
  transform: translateY(-1px);
737
  }
738
 
@@ -753,33 +810,35 @@
753
  }
754
  }
755
 
756
- /* Elegant Alert & Queues */
757
  .status-alert {
758
  display: flex;
759
  align-items: center;
760
  gap: 10px;
761
- font-size: 0.85rem;
762
  font-weight: 500;
763
  padding: 10px 14px;
764
  border-radius: var(--radius-md);
765
  border: 1px solid transparent;
766
  display: none;
 
 
767
  }
768
 
769
  .status-alert.success {
770
- background: rgba(16, 185, 129, 0.06);
771
  border-color: rgba(16, 185, 129, 0.15);
772
  color: var(--accent-green);
773
  }
774
 
775
  .status-alert.info {
776
- background: rgba(139, 92, 246, 0.06);
777
- border-color: rgba(139, 92, 246, 0.15);
778
- color: #a78bfa;
779
  }
780
 
781
  .status-alert.error {
782
- background: rgba(239, 68, 68, 0.06);
783
  border-color: rgba(239, 68, 68, 0.15);
784
  color: #f87171;
785
  }
@@ -793,39 +852,21 @@
793
  animation: spin 0.8s linear infinite;
794
  }
795
 
796
- /* Clean Selector Capsules for Quick Demos */
797
- .demo-deck {
798
- display: flex;
799
- flex-direction: column;
800
- gap: 10px;
801
  }
802
 
 
803
  .demo-capsules {
804
  display: flex;
805
  flex-direction: column;
806
  gap: 8px;
807
- max-height: 240px;
808
- overflow-y: auto;
809
- padding-right: 2px;
810
- }
811
-
812
- .demo-capsules::-webkit-scrollbar {
813
- width: 4px;
814
- }
815
-
816
- .demo-capsules::-webkit-scrollbar-track {
817
- background: rgba(255, 255, 255, 0.01);
818
- border-radius: 2px;
819
- }
820
-
821
- .demo-capsules::-webkit-scrollbar-thumb {
822
- background: rgba(255, 255, 255, 0.08);
823
- border-radius: 2px;
824
  }
825
 
826
  .demo-pill {
827
  background: rgba(255, 255, 255, 0.01);
828
- border: 1px solid var(--panel-border);
829
  border-radius: var(--radius-md);
830
  padding: 10px 14px;
831
  cursor: pointer;
@@ -838,24 +879,24 @@
838
  }
839
 
840
  .demo-pill:hover {
841
- background: rgba(255, 255, 255, 0.03);
842
- border-color: rgba(255, 255, 255, 0.12);
843
- transform: translateX(1px);
844
  }
845
 
846
  .demo-pill.active {
847
- border-color: var(--accent-orange);
848
- background: rgba(255, 107, 53, 0.03);
849
  }
850
 
851
  .demo-pill-title {
852
- font-size: 0.85rem;
853
  font-weight: 600;
854
  color: #ffffff;
855
  white-space: nowrap;
856
  overflow: hidden;
857
  text-overflow: ellipsis;
858
- max-width: 180px;
859
  }
860
 
861
  .pill-labels {
@@ -872,49 +913,49 @@
872
  text-transform: uppercase;
873
  }
874
 
875
- .pill-badge-male { background: rgba(59, 130, 246, 0.1); color: #60a5fa; }
876
- .pill-badge-female { background: rgba(236, 72, 153, 0.1); color: #f472b6; }
877
- .pill-badge-long { background: rgba(139, 92, 246, 0.1); color: #c084fc; }
878
-
879
- /* Minimalist Accordion Guide */
880
- .guide-deck {
881
- border-top: 1px solid rgba(255, 255, 255, 0.04);
882
- padding-top: 16px;
883
- }
884
 
 
885
  .guide-header {
886
- font-size: 0.85rem;
887
- font-weight: 600;
888
  color: #ffffff;
889
  cursor: pointer;
890
  display: flex;
891
  justify-content: space-between;
892
  align-items: center;
893
  user-select: none;
 
 
 
 
 
894
  }
895
 
896
  .guide-body {
897
  max-height: 0;
898
  overflow: hidden;
899
  transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
900
- font-size: 0.8rem;
901
  color: var(--text-secondary);
902
  display: flex;
903
  flex-direction: column;
904
- gap: 10px;
905
- line-height: 1.5;
906
  }
907
 
908
  .guide-body.open {
909
  max-height: 380px;
910
- margin-top: 10px;
911
  }
912
 
913
  .guide-block-title {
914
  color: #ffffff;
915
  font-weight: 600;
916
  margin-bottom: 2px;
917
- font-size: 0.8rem;
918
  }
919
 
920
  .guide-list {
@@ -924,6 +965,26 @@
924
  gap: 3px;
925
  }
926
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
  footer {
928
  margin-top: auto;
929
  text-align: center;
@@ -932,230 +993,131 @@
932
  color: var(--text-secondary);
933
  border-top: 1px solid rgba(255, 255, 255, 0.03);
934
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935
  </style>
936
  </head>
937
  <body>
938
 
939
- <div class="container">
940
- <header>
941
- <div class="logo-area">
942
- <span class="logo-emoji">🎭</span>
943
- <h1>DramaBox</h1>
 
 
944
  </div>
945
- <div class="subtitle">Expressive TTS with Voice Cloning</div>
946
 
947
- <div class="ltx-banner">
948
- πŸ—οΈ&nbsp; Built on <a href="https://github.com/Lightricks/LTX-2" target="_blank">LTX-2</a> by
949
- <a href="https://huggingface.co/Lightricks" target="_blank">Lightricks</a>.
950
- <strong>DramaBox</strong> is <strong>Resemble AI's</strong> expressive TTS,
951
- trained on top of the LTX-2.3 audio branch under the LTX-2 Community License.
952
- Huge thanks to the Lightricks team for open-sourcing the base.
953
- </div>
954
- </header>
955
-
956
- <main>
957
- <!-- Left Side: Custom Configuration Card -->
958
- <section class="card">
959
- <div class="card-header">
960
- <span>πŸͺ„</span> Input Board
961
- </div>
962
-
963
- <!-- Textarea Script -->
964
  <div class="form-group">
965
- <div class="form-label">
966
- <span>Script Prompt</span>
967
- <span class="label-badge">Double quotes for dialogue, standard text for style</span>
968
- </div>
969
- <textarea
970
- id="scene-prompt"
971
- class="textarea-custom"
972
- placeholder='A shadowy villain speaks with cold menace, "You have entered my domain, mortal." He chuckles darkly, "Such arrogance will be your undoing."'
973
- ></textarea>
974
- </div>
975
-
976
- <!-- Modern Reference File Uploader -->
977
- <div class="form-group">
978
- <div class="form-label">
979
- <span>Timbre Reference (Optional)</span>
980
- <span>10s+ file</span>
981
- </div>
982
-
983
  <div id="dropzone" class="upload-zone">
984
  <span class="upload-icon">πŸ“€</span>
985
  <div class="upload-text">
986
  <strong>Drop file</strong> or click to choose<br>
987
- <span>Supports WAV, MP3, etc.</span>
988
  </div>
989
  </div>
990
  <input type="file" id="audio-file" class="hidden-input" accept="audio/*">
991
  </div>
992
 
993
- <!-- Dynamic Accordion Panel -->
994
- <div class="settings-accordion">
995
- <button type="button" class="accordion-header" id="accordion-toggle">
996
- <span>βš™οΈ Settings Dashboard</span>
997
- <span class="accordion-icon" id="accordion-arrow">β–Ό</span>
998
- </button>
999
 
1000
- <div class="accordion-body" id="accordion-panel">
1001
- <!-- CFG Scale -->
1002
- <div class="slider-group">
1003
- <div class="slider-meta">
1004
- <span>CFG Scale</span>
1005
- <span class="slider-value" id="val-cfg">2.5</span>
1006
- </div>
1007
- <input type="range" id="cfg" min="1.0" max="10.0" step="0.5" value="2.5">
1008
- </div>
1009
-
1010
- <!-- STG Scale -->
1011
- <div class="slider-group">
1012
- <div class="slider-meta">
1013
- <span>STG Scale</span>
1014
- <span class="slider-value" id="val-stg">1.5</span>
1015
- </div>
1016
- <input type="range" id="stg" min="0.0" max="5.0" step="0.5" value="1.5">
1017
- </div>
1018
-
1019
- <!-- Duration factor -->
1020
- <div class="slider-group">
1021
- <div class="slider-meta">
1022
- <span>Breathing Room Factor</span>
1023
- <span class="slider-value" id="val-dur">1.10</span>
1024
- </div>
1025
- <input type="range" id="dur" min="0.8" max="2.0" step="0.05" value="1.1">
1026
- </div>
1027
-
1028
- <!-- Target Length -->
1029
- <div class="slider-group">
1030
- <div class="slider-meta">
1031
- <span>Fixed duration (s) - 0 = Auto</span>
1032
- <span class="slider-value" id="val-gendur">0.0</span>
1033
- </div>
1034
- <input type="range" id="gendur" min="0.0" max="60.0" step="1.0" value="0.0">
1035
  </div>
 
 
1036
 
1037
- <!-- Reference window -->
1038
- <div class="slider-group">
1039
- <div class="slider-meta">
1040
- <span>Reference window (s)</span>
1041
- <span class="slider-value" id="val-refdur">10.0</span>
1042
- </div>
1043
- <input type="range" id="refdur" min="3.0" max="30.0" step="1.0" value="10.0">
1044
  </div>
 
 
1045
 
1046
- <!-- Seed Input -->
1047
- <div class="form-group">
1048
- <span class="form-label">Seed Value</span>
1049
- <div class="seed-row">
1050
- <input type="number" id="seed" class="input-seed" value="42">
1051
- <button type="button" id="btn-random-seed" class="btn-seed-random" title="Randomize Seed">🎲</button>
1052
- </div>
1053
  </div>
 
1054
  </div>
1055
- </div>
1056
-
1057
- <!-- Generate Click -->
1058
- <button id="btn-generate" class="btn-generate">
1059
- <span>⚑</span> Generate Speech
1060
- </button>
1061
- </section>
1062
-
1063
- <!-- Right Side: Status, Player, Demos & Guides -->
1064
- <section class="card">
1065
- <div class="card-header">
1066
- <span>πŸ”Š</span> Output Lounge
1067
- </div>
1068
-
1069
- <!-- State alerts -->
1070
- <div id="status-box" class="status-alert">
1071
- <div class="alert-spinner"></div>
1072
- <span id="status-text">Synchronizing Engine...</span>
1073
- </div>
1074
 
1075
- <!-- Audio visualizer & controller -->
1076
- <div class="output-wrapper">
1077
- <audio id="audio-element" style="display:none;"></audio>
1078
-
1079
- <!-- Default Screen -->
1080
- <div id="output-empty-state" class="empty-placeholder">
1081
- <span class="empty-icon">🎚️</span>
1082
- <span class="empty-text">Formulate a script above to voice speech</span>
1083
  </div>
1084
 
1085
- <!-- Audio Player Deck -->
1086
- <div id="custom-player" class="audio-player" style="display: none;">
1087
- <div class="visualizer-box">
1088
- <div class="visualizer-wave">
1089
- <span class="wave-bar"></span>
1090
- <span class="wave-bar"></span>
1091
- <span class="wave-bar"></span>
1092
- <span class="wave-bar"></span>
1093
- <span class="wave-bar"></span>
1094
- <span class="wave-bar"></span>
1095
- <span class="wave-bar"></span>
1096
- <span class="wave-bar"></span>
1097
- <span class="wave-bar"></span>
1098
- <span class="wave-bar"></span>
1099
- <span class="wave-bar"></span>
1100
- <span class="wave-bar"></span>
1101
- <span class="wave-bar"></span>
1102
- <span class="wave-bar"></span>
1103
- <span class="wave-bar"></span>
1104
- <span class="wave-bar"></span>
1105
- <span class="wave-bar"></span>
1106
- <span class="wave-bar"></span>
1107
- <span class="wave-bar"></span>
1108
- <span class="wave-bar"></span>
1109
- </div>
1110
- </div>
1111
-
1112
- <div class="player-row">
1113
- <button type="button" id="player-play" class="btn-play">β–Ά</button>
1114
- <div class="progress-box">
1115
- <span id="player-current-time" class="time-lbl">00:00</span>
1116
- <input type="range" id="player-progress" min="0" max="100" value="0">
1117
- <span id="player-duration" class="time-lbl">00:00</span>
1118
- </div>
1119
  </div>
 
 
1120
 
1121
- <div class="deck-footer">
1122
- <!-- Volume slider -->
1123
- <div class="vol-slider">
1124
- <span class="vol-icon">πŸ”Š</span>
1125
- <input type="range" id="player-volume" min="0" max="1" step="0.1" value="0.8">
1126
- </div>
1127
-
1128
- <!-- Speeds selector -->
1129
- <div class="speed-deck">
1130
- <button type="button" class="btn-speed" data-speed="0.8">0.8x</button>
1131
- <button type="button" class="btn-speed active" data-speed="1.0">1.0x</button>
1132
- <button type="button" class="btn-speed" data-speed="1.2">1.2x</button>
1133
- <button type="button" class="btn-speed" data-speed="1.5">1.5x</button>
1134
- </div>
1135
-
1136
- <!-- Direct WAV file downloading -->
1137
- <a id="player-download" class="btn-download-wav" href="#" download="dramabox_audio.wav">
1138
- <span>πŸ“₯</span> Download
1139
- </a>
1140
  </div>
1141
  </div>
1142
  </div>
1143
 
1144
- <!-- Custom Selector Capsules for Quick Demos -->
1145
- <div class="demo-deck">
1146
- <div class="form-label" style="margin-bottom: 2px;">
1147
- <span>Quick Demos</span>
1148
- <span>Click to pre-populate</span>
1149
- </div>
1150
  <div class="demo-capsules" id="examples-container">
1151
  <!-- Loaded dynamically -->
1152
  </div>
1153
  </div>
1154
 
1155
- <!-- Minimalist Guide Accordion -->
1156
- <div class="guide-deck">
1157
  <div class="guide-header" id="guide-toggle">
1158
- <span>πŸ“– Prompt Structure Guide</span>
1159
  <span class="accordion-icon" id="guide-arrow">β–Ό</span>
1160
  </div>
1161
 
@@ -1165,30 +1127,157 @@
1165
  <p><code>&lt;description&gt;, "&lt;dialogue&gt;" &lt;movement/breath&gt; "&lt;more dialogue&gt;"</code></p>
1166
  </div>
1167
  <div>
1168
- <div class="guide-block-title">Inside Quotes (Model pronounces)</div>
1169
  <ul class="guide-list">
1170
- <li>Spoken transcript: <code>"We have achieved full takeoff."</code></li>
1171
  <li>Phonetic expressions: <code>"Hahaha"</code>, <code>"Mmmm"</code>, <code>"Ugh"</code>, <code>"Argh"</code></li>
1172
  </ul>
1173
  </div>
1174
  <div>
1175
- <div class="guide-block-title">Outside Quotes (Stage Directions)</div>
1176
  <ul class="guide-list">
1177
- <li>Pacing/acting styles: <code>She sighs deeply.</code>, <code>A long pause.</code></li>
1178
  <li>Tonal delivery: <code>His voice cracks.</code>, <code>He clears his throat.</code></li>
1179
  </ul>
1180
  </div>
1181
  </div>
1182
  </div>
1183
- </section>
1184
- </main>
1185
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1186
 
1187
- <footer>
1188
- &copy; 2026 DramaBox. Generative speech outputs are invisibly watermarked with Resemble Perth.
1189
- </footer>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1190
 
1191
- <!-- Gradio Connection Module -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1192
  <script type="module">
1193
  import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
1194
 
@@ -1288,6 +1377,11 @@
1288
  let selectedAudioFilename = "";
1289
 
1290
  // UI nodes
 
 
 
 
 
1291
  const statusBox = document.getElementById("status-box");
1292
  const statusText = document.getElementById("status-text");
1293
  const btnGenerate = document.getElementById("btn-generate");
@@ -1296,11 +1390,6 @@
1296
  const dropzone = document.getElementById("dropzone");
1297
  const audioFileInput = document.getElementById("audio-file");
1298
 
1299
- // Accordion Nodes
1300
- const accordionToggle = document.getElementById("accordion-toggle");
1301
- const accordionPanel = document.getElementById("accordion-panel");
1302
- const accordionArrow = document.getElementById("accordion-arrow");
1303
-
1304
  // Settings sliders
1305
  const sliderCfg = document.getElementById("cfg");
1306
  const valCfg = document.getElementById("val-cfg");
@@ -1333,6 +1422,30 @@
1333
  const guideBody = document.getElementById("guide-body");
1334
  const guideArrow = document.getElementById("guide-arrow");
1335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1336
  // Simple alert helper
1337
  function updateStatus(message, type = "info", showSpinner = true) {
1338
  statusBox.style.display = "flex";
@@ -1365,11 +1478,6 @@
1365
  }
1366
 
1367
  // Accordion animations
1368
- accordionToggle.addEventListener("click", () => {
1369
- const isOpen = accordionPanel.classList.toggle("open");
1370
- accordionArrow.innerText = isOpen ? "β–²" : "β–Ό";
1371
- });
1372
-
1373
  guideToggle.addEventListener("click", () => {
1374
  const isOpen = guideBody.classList.toggle("open");
1375
  guideArrow.innerText = isOpen ? "β–²" : "β–Ό";
@@ -1428,7 +1536,7 @@
1428
  <div class="file-capsule">
1429
  <div class="file-info">
1430
  <span>🎡</span>
1431
- <span style="overflow: hidden; text-overflow: ellipsis;">${filename}</span>
1432
  </div>
1433
  <button type="button" class="btn-clear" id="btn-clear-upload" title="Remove voice file">βœ•</button>
1434
  </div>
@@ -1447,7 +1555,7 @@
1447
  <span class="upload-icon">πŸ“€</span>
1448
  <div class="upload-text">
1449
  <strong>Drop file</strong> or click to choose<br>
1450
- <span>Supports WAV, MP3, etc.</span>
1451
  </div>
1452
  `;
1453
  }
@@ -1499,6 +1607,11 @@
1499
 
1500
  const filename = ex.voice.substring(ex.voice.lastIndexOf('/') + 1);
1501
  loadExampleVoice(ex.voice, filename);
 
 
 
 
 
1502
  });
1503
 
1504
  examplesContainer.appendChild(pill);
@@ -1600,7 +1713,7 @@
1600
 
1601
  try {
1602
  btnGenerate.disabled = true;
1603
- btnGenerate.innerHTML = `<div class="alert-spinner"></div> Voice Synthesis...`;
1604
  updateStatus("Checking models & processing queues...", "info");
1605
 
1606
  let uploadedFileData = null;
 
7
 
8
  <!-- Meta tags for premium look and SEO -->
9
  <meta name="description" content="Generate highly expressive speech with voice cloning. Powered by LTX-2.3 and Resemble Perth watermarking.">
10
+ <meta name="theme-color" content="#07090e">
11
 
12
  <!-- Google Fonts: Outfit and Inter -->
13
  <link rel="preconnect" href="https://fonts.googleapis.com">
 
16
 
17
  <style>
18
  :root {
19
+ --bg-color: #05060a;
20
+ --panel-bg: rgba(11, 14, 23, 0.75);
21
+ --sidebar-bg: #0b0e17;
22
+ --panel-border: rgba(60, 208, 162, 0.08);
23
  --text-primary: #f8fafc;
24
  --text-secondary: #94a3b8;
25
+ --accent-mint: #3cd0a2;
26
+ --accent-mint-hover: #5fe2b9;
27
+ --accent-mint-glow: rgba(60, 208, 162, 0.2);
28
+ --accent-dark-slate: #1e293b;
 
 
29
  --accent-green: #10b981;
30
+ --radius-lg: 18px;
31
  --radius-md: 12px;
32
  --radius-sm: 8px;
33
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
34
  }
35
 
36
  * {
 
45
  font-family: 'Inter', sans-serif;
46
  min-height: 100vh;
47
  line-height: 1.5;
48
+ overflow: hidden; /* Sidebar controls scrolling */
49
  position: relative;
 
 
50
  }
51
 
52
+ /* Ambient glowing circles using Resemble AI branding colors */
53
  body::before {
54
  content: '';
55
  position: absolute;
56
  top: -10%;
57
+ left: 10%;
58
+ width: 45%;
59
+ height: 45%;
60
+ background: radial-gradient(circle, var(--accent-mint-glow) 0%, transparent 60%);
61
  z-index: -1;
62
  filter: blur(80px);
63
  pointer-events: none;
64
+ opacity: 0.7;
65
  }
66
 
67
  body::after {
68
  content: '';
69
  position: absolute;
70
+ bottom: -5%;
71
  right: 5%;
72
+ width: 40%;
73
+ height: 40%;
74
+ background: radial-gradient(circle, rgba(139, 92, 246, 0.12) 0%, transparent 60%);
75
  z-index: -1;
76
  filter: blur(80px);
77
  pointer-events: none;
78
+ opacity: 0.5;
79
+ }
80
+
81
+ /* Base Page Layout */
82
+ .app-layout {
83
+ display: flex;
84
+ width: 100vw;
85
+ height: 100vh;
86
+ position: relative;
87
+ overflow: hidden;
88
+ }
89
+
90
+ /* ── Collapsible Sidebar ── */
91
+ .sidebar {
92
+ width: 360px;
93
+ height: 100%;
94
+ background-color: var(--sidebar-bg);
95
+ border-right: 1px solid var(--panel-border);
96
+ display: flex;
97
+ flex-direction: column;
98
+ position: relative;
99
+ z-index: 100;
100
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), margin-left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
101
+ box-shadow: 10px 0 30px rgba(0, 0, 0, 0.25);
102
+ flex-shrink: 0;
103
+ }
104
+
105
+ .sidebar.collapsed {
106
+ margin-left: -360px;
107
+ transform: translateX(-100%);
108
+ }
109
+
110
+ .sidebar-header {
111
+ padding: 20px 24px;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: space-between;
115
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
116
+ }
117
+
118
+ .sidebar-title {
119
+ font-family: 'Outfit', sans-serif;
120
+ font-size: 1.1rem;
121
+ font-weight: 700;
122
+ color: #ffffff;
123
+ letter-spacing: 0.5px;
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 8px;
127
+ }
128
+
129
+ .sidebar-close-btn {
130
+ background: none;
131
+ border: none;
132
+ color: var(--text-secondary);
133
+ font-size: 1.1rem;
134
+ cursor: pointer;
135
+ transition: var(--transition);
136
+ display: flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ padding: 4px;
140
+ }
141
+
142
+ .sidebar-close-btn:hover {
143
+ color: #ffffff;
144
+ transform: scale(1.1);
145
+ }
146
+
147
+ .sidebar-scrollable {
148
+ flex: 1;
149
+ overflow-y: auto;
150
+ padding: 24px;
151
+ display: flex;
152
+ flex-direction: column;
153
+ gap: 24px;
154
+ }
155
+
156
+ /* Scrollbar styles for sidebar */
157
+ .sidebar-scrollable::-webkit-scrollbar {
158
+ width: 5px;
159
+ }
160
+
161
+ .sidebar-scrollable::-webkit-scrollbar-track {
162
+ background: transparent;
163
+ }
164
+
165
+ .sidebar-scrollable::-webkit-scrollbar-thumb {
166
+ background: rgba(255, 255, 255, 0.05);
167
+ border-radius: 3px;
168
+ }
169
+
170
+ .sidebar-scrollable::-webkit-scrollbar-thumb:hover {
171
+ background: rgba(255, 255, 255, 0.1);
172
+ }
173
+
174
+ /* ── Main Workspace Area ── */
175
+ .content-area {
176
+ flex: 1;
177
+ height: 100%;
178
+ display: flex;
179
+ flex-direction: column;
180
+ overflow-y: auto;
181
+ position: relative;
182
+ transition: var(--transition);
183
  }
184
 
185
+ /* Main Scrollable wrapper */
186
+ .content-container {
187
  width: 100%;
188
+ max-width: 840px;
189
  margin: 0 auto;
190
+ padding: 24px 20px 60px 20px;
191
  display: flex;
192
  flex-direction: column;
193
  gap: 24px;
 
200
  text-align: center;
201
  padding: 20px 0 10px 0;
202
  gap: 12px;
203
+ position: relative;
204
  }
205
 
206
  .logo-area {
 
221
 
222
  h1 {
223
  font-family: 'Outfit', sans-serif;
224
+ font-size: 2.4rem;
225
  font-weight: 800;
226
+ background: linear-gradient(135deg, #ffffff 40%, var(--accent-mint) 80%, #76ecd4 100%);
227
  -webkit-background-clip: text;
228
  -webkit-text-fill-color: transparent;
229
  letter-spacing: -0.5px;
230
  }
231
 
232
+ .brand-badge {
233
+ font-size: 0.75rem;
234
+ font-weight: 600;
235
+ background: rgba(60, 208, 162, 0.1);
236
+ color: var(--accent-mint);
237
+ border: 1px solid rgba(60, 208, 162, 0.2);
238
+ padding: 3px 8px;
239
+ border-radius: 30px;
240
+ text-transform: uppercase;
241
+ letter-spacing: 0.5px;
242
+ }
243
+
244
  .subtitle {
245
+ font-size: 0.95rem;
246
  color: var(--text-secondary);
247
  font-weight: 400;
 
248
  }
249
 
250
  .ltx-banner {
251
+ background: rgba(22, 28, 45, 0.3);
252
  border: 1px solid var(--panel-border);
253
+ border-left: 3px solid var(--accent-mint);
254
  border-radius: var(--radius-md);
255
  padding: 12px 18px;
256
  color: #cbd5e1;
257
+ font-size: 0.82rem;
258
+ line-height: 1.5;
 
259
  text-align: left;
260
+ backdrop-filter: blur(10px);
261
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
262
+ width: 100%;
263
  }
264
 
265
  .ltx-banner a {
266
+ color: var(--accent-mint);
267
  font-weight: 600;
268
  text-decoration: none;
269
  transition: var(--transition);
 
274
  text-decoration: underline;
275
  }
276
 
277
+ /* Sliding Toggle Controls Button */
278
+ .btn-toggle-sidebar {
279
+ background: rgba(255, 255, 255, 0.03);
280
+ border: 1px solid var(--panel-border);
281
+ color: #ffffff;
282
+ font-size: 0.85rem;
283
+ font-weight: 600;
284
+ padding: 10px 16px;
285
+ border-radius: 30px;
286
+ cursor: pointer;
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 8px;
290
+ transition: var(--transition);
291
+ outline: none;
292
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
 
 
293
  }
294
 
295
+ .btn-toggle-sidebar:hover {
296
+ background: rgba(60, 208, 162, 0.05);
297
+ border-color: var(--accent-mint);
298
+ transform: translateY(-1px);
 
 
 
 
 
 
 
 
299
  }
300
 
301
+ /* ── Modern Script Panels (Main Area) ── */
302
+ .main-panel {
303
  background: var(--panel-bg);
304
  border: 1px solid var(--panel-border);
305
  border-radius: var(--radius-lg);
306
  padding: 24px;
307
  backdrop-filter: blur(20px);
308
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.25);
309
  display: flex;
310
  flex-direction: column;
311
  gap: 20px;
312
  transition: var(--transition);
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  .form-group {
316
  display: flex;
317
  flex-direction: column;
 
319
  }
320
 
321
  .form-label {
322
+ font-size: 0.78rem;
323
+ font-weight: 700;
324
  text-transform: uppercase;
325
  letter-spacing: 0.8px;
326
  color: var(--text-secondary);
 
331
 
332
  .label-badge {
333
  font-size: 0.75rem;
334
+ color: var(--accent-mint);
335
  text-transform: none;
336
  font-weight: 400;
337
  letter-spacing: 0;
 
339
 
340
  .textarea-custom {
341
  width: 100%;
342
+ background: rgba(5, 7, 12, 0.8);
343
  border: 1px solid var(--panel-border);
344
  border-radius: var(--radius-md);
345
+ padding: 16px;
346
  color: var(--text-primary);
347
  font-family: 'Inter', sans-serif;
348
+ font-size: 1rem;
349
+ line-height: 1.6;
350
  resize: vertical;
351
+ min-height: 140px;
352
  outline: none;
353
  transition: var(--transition);
354
  }
355
 
356
  .textarea-custom:focus {
357
+ border-color: var(--accent-mint);
358
+ box-shadow: 0 0 15px var(--accent-mint-glow);
359
+ background: rgba(5, 7, 12, 0.95);
360
  }
361
 
362
+ /* Reference Uploader Inside Sidebar */
363
  .upload-zone {
364
+ border: 2px dashed rgba(60, 208, 162, 0.2);
365
  border-radius: var(--radius-md);
366
+ padding: 18px;
367
  text-align: center;
368
  cursor: pointer;
369
+ background: rgba(60, 208, 162, 0.01);
370
  display: flex;
371
  flex-direction: column;
372
  align-items: center;
373
+ gap: 6px;
374
  transition: var(--transition);
375
+ min-height: 90px;
376
  justify-content: center;
377
  }
378
 
379
  .upload-zone:hover, .upload-zone.dragover {
380
+ border-color: var(--accent-mint);
381
+ background: rgba(60, 208, 162, 0.04);
382
  }
383
 
384
  .upload-icon {
385
+ font-size: 1.6rem;
386
+ color: var(--accent-mint);
387
  transition: var(--transition);
388
  }
389
 
 
 
 
 
 
390
  .upload-text {
391
+ font-size: 0.8rem;
392
  color: var(--text-secondary);
393
  }
394
 
 
397
  font-weight: 500;
398
  }
399
 
 
 
 
 
 
400
  .file-capsule {
401
  display: flex;
402
  align-items: center;
403
  justify-content: space-between;
404
+ background: rgba(60, 208, 162, 0.06);
405
+ border: 1px solid rgba(60, 208, 162, 0.2);
406
  padding: 10px 14px;
407
  border-radius: var(--radius-md);
408
  width: 100%;
 
412
  display: flex;
413
  align-items: center;
414
  gap: 10px;
415
+ font-size: 0.82rem;
416
  font-weight: 500;
417
  overflow: hidden;
418
  white-space: nowrap;
 
423
  background: none;
424
  border: none;
425
  color: var(--text-secondary);
426
+ font-size: 0.95rem;
427
  cursor: pointer;
428
  transition: var(--transition);
429
  padding: 2px;
 
437
  transform: scale(1.1);
438
  }
439
 
440
+ /* Modernized Sidebar Dashboard Items */
441
+ .settings-block {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  display: flex;
443
  flex-direction: column;
444
  gap: 16px;
445
+ background: rgba(255, 255, 255, 0.01);
446
+ border: 1px solid rgba(255, 255, 255, 0.03);
447
+ padding: 16px;
448
+ border-radius: var(--radius-md);
449
  }
450
 
451
+ .settings-block-title {
452
+ font-family: 'Outfit', sans-serif;
453
+ font-size: 0.85rem;
454
+ font-weight: 700;
455
+ letter-spacing: 0.5px;
456
+ text-transform: uppercase;
457
+ color: #ffffff;
458
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
459
+ padding-bottom: 8px;
460
+ margin-bottom: 4px;
461
  }
462
 
463
  .slider-group {
 
475
  }
476
 
477
  .slider-value {
478
+ color: var(--accent-mint);
479
  font-weight: 700;
480
  font-family: monospace;
481
  }
482
 
 
483
  input[type="range"] {
484
  -webkit-appearance: none;
485
  width: 100%;
486
+ height: 4px;
487
  background: rgba(255, 255, 255, 0.06);
488
+ border-radius: 2px;
489
  outline: none;
490
  cursor: pointer;
491
  }
 
495
  width: 14px;
496
  height: 14px;
497
  border-radius: 50%;
498
+ background: var(--accent-mint);
499
+ box-shadow: 0 0 8px var(--accent-mint-glow);
500
  transition: var(--transition);
501
  }
502
 
 
505
  background: #ffffff;
506
  }
507
 
508
+ /* Seed Elements */
509
  .seed-row {
510
  display: flex;
511
  gap: 8px;
 
514
 
515
  .input-seed {
516
  flex: 1;
517
+ background: rgba(5, 7, 12, 0.8);
518
+ border: 1px solid rgba(255, 255, 255, 0.04);
519
  border-radius: var(--radius-sm);
520
+ padding: 8px 12px;
521
  color: var(--text-primary);
522
  font-family: monospace;
523
  outline: none;
524
+ font-size: 0.85rem;
525
  transition: var(--transition);
526
+ height: 38px;
527
  }
528
 
529
  .input-seed:focus {
530
+ border-color: var(--accent-mint);
531
  }
532
 
533
  .btn-seed-random {
534
  background: rgba(255, 255, 255, 0.03);
535
+ border: 1px solid rgba(255, 255, 255, 0.04);
536
  border-radius: var(--radius-sm);
537
  color: var(--text-primary);
538
+ height: 38px;
539
+ width: 38px;
540
  display: flex;
541
  align-items: center;
542
  justify-content: center;
543
  cursor: pointer;
544
  transition: var(--transition);
545
+ font-size: 0.9rem;
546
  }
547
 
548
  .btn-seed-random:hover {
549
+ background: rgba(60, 208, 162, 0.05);
550
+ border-color: var(--accent-mint);
551
  }
552
 
553
+ /* Glowing Resemble Green Button */
554
  .btn-generate {
555
+ background: linear-gradient(135deg, var(--accent-mint) 0%, #2ac596 100%);
556
  border: none;
557
  border-radius: var(--radius-md);
558
+ color: #07090e;
559
  font-family: 'Outfit', sans-serif;
560
  font-size: 1.05rem;
561
+ font-weight: 800;
562
  padding: 14px;
563
  cursor: pointer;
564
  transition: var(--transition);
 
566
  align-items: center;
567
  justify-content: center;
568
  gap: 10px;
569
+ box-shadow: 0 6px 20px var(--accent-mint-glow);
570
  min-height: 48px;
571
+ letter-spacing: 0.3px;
572
  }
573
 
574
  .btn-generate:hover:not(:disabled) {
575
  transform: translateY(-1.5px);
576
+ box-shadow: 0 10px 25px rgba(60, 208, 162, 0.4);
577
+ background: linear-gradient(135deg, var(--accent-mint-hover) 0%, var(--accent-mint) 100%);
578
  }
579
 
580
  .btn-generate:active:not(:disabled) {
 
582
  }
583
 
584
  .btn-generate:disabled {
585
+ background: #161a24;
586
+ color: #3b4255;
587
  cursor: not-allowed;
588
  box-shadow: none;
589
  }
590
 
591
+ /* ── Output Lounge (Visual Player Deck) ── */
592
  .output-wrapper {
593
+ background: rgba(5, 7, 12, 0.5);
594
  border: 1px solid var(--panel-border);
595
  border-radius: var(--radius-md);
596
  padding: 20px;
 
598
  flex-direction: column;
599
  align-items: center;
600
  justify-content: center;
601
+ min-height: 140px;
602
  position: relative;
603
  }
604
 
 
614
  .empty-icon {
615
  font-size: 2.2rem;
616
  opacity: 0.4;
617
+ color: var(--accent-mint);
618
  }
619
 
620
  .empty-text {
621
  font-size: 0.85rem;
622
  }
623
 
624
+ /* Glowing Custom Player Layout */
625
  .audio-player {
626
  width: 100%;
627
  display: flex;
 
631
 
632
  .visualizer-box {
633
  width: 100%;
634
+ height: 44px;
635
+ background: linear-gradient(90deg, rgba(60, 208, 162, 0.05) 0%, rgba(139, 92, 246, 0.03) 100%);
636
  border-radius: var(--radius-sm);
637
  display: flex;
638
  align-items: center;
639
  justify-content: center;
640
+ border: 1px solid rgba(60, 208, 162, 0.04);
641
  overflow: hidden;
642
  }
643
 
 
650
 
651
  .wave-bar {
652
  width: 3px;
653
+ height: 5px;
654
+ background: var(--accent-mint);
655
  border-radius: 1px;
656
  transition: var(--transition);
657
  }
 
661
  }
662
 
663
  @keyframes playWave {
664
+ 0% { height: 5px; }
665
+ 100% { height: 28px; }
666
  }
667
 
668
+ .wave-bar:nth-child(2n) { background: #5fe2b9; animation-delay: 0.15s; }
669
  .wave-bar:nth-child(3n) { animation-delay: 0.3s; }
670
  .wave-bar:nth-child(4n) { animation-delay: 0.45s; }
671
+ .wave-bar:nth-child(5n) { background: var(--accent-mint); animation-delay: 0.6s; }
672
 
673
  .player-row {
674
  display: flex;
 
707
  }
708
 
709
  .time-lbl {
710
+ font-size: 0.72rem;
711
  color: var(--text-secondary);
712
  font-family: monospace;
713
  min-width: 32px;
714
  }
715
 
716
+ /* Secondary progress slider bar track styling */
717
+ .progress-box input[type="range"]::-webkit-slider-thumb {
718
+ background: #ffffff;
719
+ box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
720
+ }
721
+
722
  .deck-footer {
723
  display: flex;
724
  align-items: center;
 
734
  display: flex;
735
  align-items: center;
736
  gap: 6px;
737
+ max-width: 90px;
738
  flex-shrink: 0;
739
  }
740
 
741
  .vol-icon {
742
+ font-size: 0.8rem;
743
  color: var(--text-secondary);
744
  }
745
 
746
+ .vol-slider input[type="range"]::-webkit-slider-thumb {
747
+ background: var(--text-secondary);
748
+ }
749
+
750
  .speed-deck {
751
  display: flex;
752
  align-items: center;
 
755
 
756
  .btn-speed {
757
  background: rgba(255, 255, 255, 0.02);
758
+ border: 1px solid rgba(255, 255, 255, 0.04);
759
  border-radius: 6px;
760
  color: var(--text-secondary);
761
+ font-size: 0.68rem;
762
  font-weight: 600;
763
  padding: 3px 6px;
764
  cursor: pointer;
 
766
  }
767
 
768
  .btn-speed.active, .btn-speed:hover {
769
+ background: rgba(60, 208, 162, 0.06);
770
+ color: var(--accent-mint);
771
+ border-color: rgba(60, 208, 162, 0.2);
772
  }
773
 
774
  .btn-download-wav {
 
776
  border: 1px solid var(--panel-border);
777
  border-radius: var(--radius-sm);
778
  color: #ffffff;
779
+ font-size: 0.78rem;
780
  font-weight: 600;
781
  padding: 6px 12px;
782
  text-decoration: none;
 
787
  }
788
 
789
  .btn-download-wav:hover {
790
+ background: var(--accent-mint);
791
+ color: #07090e;
792
+ border-color: var(--accent-mint);
793
  transform: translateY(-1px);
794
  }
795
 
 
810
  }
811
  }
812
 
813
+ /* Synchronizer Status Alert */
814
  .status-alert {
815
  display: flex;
816
  align-items: center;
817
  gap: 10px;
818
+ font-size: 0.82rem;
819
  font-weight: 500;
820
  padding: 10px 14px;
821
  border-radius: var(--radius-md);
822
  border: 1px solid transparent;
823
  display: none;
824
+ margin-bottom: 12px;
825
+ width: 100%;
826
  }
827
 
828
  .status-alert.success {
829
+ background: rgba(16, 185, 129, 0.04);
830
  border-color: rgba(16, 185, 129, 0.15);
831
  color: var(--accent-green);
832
  }
833
 
834
  .status-alert.info {
835
+ background: rgba(60, 208, 162, 0.04);
836
+ border-color: rgba(60, 208, 162, 0.15);
837
+ color: #8bead0;
838
  }
839
 
840
  .status-alert.error {
841
+ background: rgba(239, 68, 68, 0.04);
842
  border-color: rgba(239, 68, 68, 0.15);
843
  color: #f87171;
844
  }
 
852
  animation: spin 0.8s linear infinite;
853
  }
854
 
855
+ @keyframes spin {
856
+ 0% { transform: rotate(0deg); }
857
+ 100% { transform: rotate(360deg); }
 
 
858
  }
859
 
860
+ /* Demo deck scrollable inside sidebar */
861
  .demo-capsules {
862
  display: flex;
863
  flex-direction: column;
864
  gap: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
865
  }
866
 
867
  .demo-pill {
868
  background: rgba(255, 255, 255, 0.01);
869
+ border: 1px solid rgba(255, 255, 255, 0.04);
870
  border-radius: var(--radius-md);
871
  padding: 10px 14px;
872
  cursor: pointer;
 
879
  }
880
 
881
  .demo-pill:hover {
882
+ background: rgba(60, 208, 162, 0.02);
883
+ border-color: rgba(60, 208, 162, 0.15);
884
+ transform: translateX(2px);
885
  }
886
 
887
  .demo-pill.active {
888
+ border-color: var(--accent-mint);
889
+ background: rgba(60, 208, 162, 0.03);
890
  }
891
 
892
  .demo-pill-title {
893
+ font-size: 0.82rem;
894
  font-weight: 600;
895
  color: #ffffff;
896
  white-space: nowrap;
897
  overflow: hidden;
898
  text-overflow: ellipsis;
899
+ max-width: 170px;
900
  }
901
 
902
  .pill-labels {
 
913
  text-transform: uppercase;
914
  }
915
 
916
+ .pill-badge-male { background: rgba(59, 130, 246, 0.08); color: #60a5fa; }
917
+ .pill-badge-female { background: rgba(236, 72, 153, 0.08); color: #f472b6; }
918
+ .pill-badge-long { background: rgba(139, 92, 246, 0.08); color: #c084fc; }
 
 
 
 
 
 
919
 
920
+ /* Guide container inside sidebar */
921
  .guide-header {
922
+ font-size: 0.82rem;
923
+ font-weight: 700;
924
  color: #ffffff;
925
  cursor: pointer;
926
  display: flex;
927
  justify-content: space-between;
928
  align-items: center;
929
  user-select: none;
930
+ text-transform: uppercase;
931
+ letter-spacing: 0.5px;
932
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
933
+ padding-bottom: 8px;
934
+ margin-bottom: 4px;
935
  }
936
 
937
  .guide-body {
938
  max-height: 0;
939
  overflow: hidden;
940
  transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
941
+ font-size: 0.78rem;
942
  color: var(--text-secondary);
943
  display: flex;
944
  flex-direction: column;
945
+ gap: 12px;
946
+ line-height: 1.55;
947
  }
948
 
949
  .guide-body.open {
950
  max-height: 380px;
951
+ margin-top: 12px;
952
  }
953
 
954
  .guide-block-title {
955
  color: #ffffff;
956
  font-weight: 600;
957
  margin-bottom: 2px;
958
+ font-size: 0.78rem;
959
  }
960
 
961
  .guide-list {
 
965
  gap: 3px;
966
  }
967
 
968
+ /* ── Sidebar backdrop overlay (mobile and smaller desktops) ── */
969
+ .sidebar-overlay {
970
+ position: fixed;
971
+ top: 0;
972
+ left: 0;
973
+ width: 100vw;
974
+ height: 100vh;
975
+ background: rgba(0, 0, 0, 0.5);
976
+ backdrop-filter: blur(4px);
977
+ z-index: 90;
978
+ opacity: 0;
979
+ pointer-events: none;
980
+ transition: opacity 0.3s ease;
981
+ }
982
+
983
+ .sidebar-overlay.active {
984
+ opacity: 1;
985
+ pointer-events: auto;
986
+ }
987
+
988
  footer {
989
  margin-top: auto;
990
  text-align: center;
 
993
  color: var(--text-secondary);
994
  border-top: 1px solid rgba(255, 255, 255, 0.03);
995
  }
996
+
997
+ /* ── Mobile and Tablet Adaptations ── */
998
+ @media (max-width: 992px) {
999
+ .sidebar {
1000
+ position: fixed;
1001
+ top: 0;
1002
+ left: 0;
1003
+ height: 100%;
1004
+ z-index: 1000;
1005
+ }
1006
+ .sidebar.collapsed {
1007
+ margin-left: 0;
1008
+ transform: translateX(-100%);
1009
+ }
1010
+ h1 {
1011
+ font-size: 2rem;
1012
+ }
1013
+ .logo-emoji {
1014
+ font-size: 1.8rem;
1015
+ }
1016
+ }
1017
+
1018
+ @media (min-width: 993px) {
1019
+ .sidebar-close-btn {
1020
+ display: none; /* Only show toggle trigger on desktop */
1021
+ }
1022
+ }
1023
  </style>
1024
  </head>
1025
  <body>
1026
 
1027
+ <div class="app-layout">
1028
+
1029
+ <!-- Left collapsing sidebar with configuration parameters & demos -->
1030
+ <aside id="app-sidebar" class="sidebar">
1031
+ <div class="sidebar-header">
1032
+ <span class="sidebar-title">πŸŽ›οΈ Control Deck</span>
1033
+ <button id="btn-close-sidebar" class="sidebar-close-btn" title="Close Panel">βœ•</button>
1034
  </div>
 
1035
 
1036
+ <div class="sidebar-scrollable">
1037
+ <!-- Reference Audio Uploader -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1038
  <div class="form-group">
1039
+ <span class="form-label">Voice Reference (Optional)</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  <div id="dropzone" class="upload-zone">
1041
  <span class="upload-icon">πŸ“€</span>
1042
  <div class="upload-text">
1043
  <strong>Drop file</strong> or click to choose<br>
1044
+ <span>WAV, MP3, etc. (10s+)</span>
1045
  </div>
1046
  </div>
1047
  <input type="file" id="audio-file" class="hidden-input" accept="audio/*">
1048
  </div>
1049
 
1050
+ <!-- Settings Dashboard Parameters -->
1051
+ <div class="settings-block">
1052
+ <div class="settings-block-title">Synthesis Parameters</div>
 
 
 
1053
 
1054
+ <!-- CFG Scale -->
1055
+ <div class="slider-group">
1056
+ <div class="slider-meta">
1057
+ <span>CFG Scale</span>
1058
+ <span class="slider-value" id="val-cfg">2.5</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1059
  </div>
1060
+ <input type="range" id="cfg" min="1.0" max="10.0" step="0.5" value="2.5">
1061
+ </div>
1062
 
1063
+ <!-- STG Scale -->
1064
+ <div class="slider-group">
1065
+ <div class="slider-meta">
1066
+ <span>STG Scale</span>
1067
+ <span class="slider-value" id="val-stg">1.5</span>
 
 
1068
  </div>
1069
+ <input type="range" id="stg" min="0.0" max="5.0" step="0.5" value="1.5">
1070
+ </div>
1071
 
1072
+ <!-- Duration Scale Factor -->
1073
+ <div class="slider-group">
1074
+ <div class="slider-meta">
1075
+ <span>Breathing Factor</span>
1076
+ <span class="slider-value" id="val-dur">1.10</span>
 
 
1077
  </div>
1078
+ <input type="range" id="dur" min="0.8" max="2.0" step="0.05" value="1.1">
1079
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
 
1081
+ <!-- Target Generation Time -->
1082
+ <div class="slider-group">
1083
+ <div class="slider-meta">
1084
+ <span>Fixed duration (s) - 0 = Auto</span>
1085
+ <span class="slider-value" id="val-gendur">0.0</span>
1086
+ </div>
1087
+ <input type="range" id="gendur" min="0.0" max="60.0" step="1.0" value="0.0">
 
1088
  </div>
1089
 
1090
+ <!-- Reference Window -->
1091
+ <div class="slider-group">
1092
+ <div class="slider-meta">
1093
+ <span>Reference Window (s)</span>
1094
+ <span class="slider-value" id="val-refdur">10.0</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1095
  </div>
1096
+ <input type="range" id="refdur" min="3.0" max="30.0" step="1.0" value="10.0">
1097
+ </div>
1098
 
1099
+ <!-- Seed Controls -->
1100
+ <div class="form-group">
1101
+ <span class="form-label">Seed Value</span>
1102
+ <div class="seed-row">
1103
+ <input type="number" id="seed" class="input-seed" value="42">
1104
+ <button type="button" id="btn-random-seed" class="btn-seed-random" title="Randomize Seed">🎲</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
  </div>
1106
  </div>
1107
  </div>
1108
 
1109
+ <!-- Quick Examples Selector -->
1110
+ <div class="form-group">
1111
+ <span class="form-label">Quick Demos</span>
 
 
 
1112
  <div class="demo-capsules" id="examples-container">
1113
  <!-- Loaded dynamically -->
1114
  </div>
1115
  </div>
1116
 
1117
+ <!-- Accordion Guide -->
1118
+ <div class="form-group">
1119
  <div class="guide-header" id="guide-toggle">
1120
+ <span>πŸ“– Prompt Guide</span>
1121
  <span class="accordion-icon" id="guide-arrow">β–Ό</span>
1122
  </div>
1123
 
 
1127
  <p><code>&lt;description&gt;, "&lt;dialogue&gt;" &lt;movement/breath&gt; "&lt;more dialogue&gt;"</code></p>
1128
  </div>
1129
  <div>
1130
+ <div class="guide-block-title">Inside Quotes (Spoken)</div>
1131
  <ul class="guide-list">
1132
+ <li>Dialogue transcript: <code>"We are in position."</code></li>
1133
  <li>Phonetic expressions: <code>"Hahaha"</code>, <code>"Mmmm"</code>, <code>"Ugh"</code>, <code>"Argh"</code></li>
1134
  </ul>
1135
  </div>
1136
  <div>
1137
+ <div class="guide-block-title">Outside Quotes (Pacing)</div>
1138
  <ul class="guide-list">
1139
+ <li>Action details: <code>She sighs deeply.</code>, <code>A long pause.</code></li>
1140
  <li>Tonal delivery: <code>His voice cracks.</code>, <code>He clears his throat.</code></li>
1141
  </ul>
1142
  </div>
1143
  </div>
1144
  </div>
1145
+ </div>
1146
+ </aside>
1147
+
1148
+ <!-- Sidebar backdrop overlay (mobile and smaller screen viewports) -->
1149
+ <div id="sidebar-overlay" class="sidebar-overlay"></div>
1150
+
1151
+ <!-- Main workspace containing editing space and glowing outputs -->
1152
+ <div class="content-area">
1153
+ <div class="content-container">
1154
+ <header>
1155
+ <div class="logo-area">
1156
+ <span class="logo-emoji">🎭</span>
1157
+ <h1>DramaBox</h1>
1158
+ <span class="brand-badge">Resemble.AI</span>
1159
+ </div>
1160
+ <div class="subtitle">Expressive TTS with Voice Cloning</div>
1161
+
1162
+ <!-- Sliding Collapsible Trigger -->
1163
+ <button id="btn-toggle-sidebar" class="btn-toggle-sidebar" title="Toggle Dashboard Panel">
1164
+ <span class="toggle-icon">πŸŽ›οΈ</span>
1165
+ <span class="toggle-text">Show Control Deck & Demos</span>
1166
+ </button>
1167
+ </header>
1168
+
1169
+ <!-- State Alerts (Connecting / Queuing states) -->
1170
+ <div id="status-box" class="status-alert">
1171
+ <div class="alert-spinner"></div>
1172
+ <span id="status-text">Connecting to DramaBox API...</span>
1173
+ </div>
1174
+
1175
+ <main class="main-panel">
1176
+ <!-- Script Prompt Input -->
1177
+ <div class="form-group">
1178
+ <div class="form-label">
1179
+ <span>Script Prompt</span>
1180
+ <span class="label-badge">Double quotes for dialogue, standard text for style</span>
1181
+ </div>
1182
+ <textarea
1183
+ id="scene-prompt"
1184
+ class="textarea-custom"
1185
+ placeholder='A shadowy villain speaks with cold menace, "You have entered my domain, mortal." He chuckles darkly, "Such arrogance will be your undoing."'
1186
+ ></textarea>
1187
+ </div>
1188
+
1189
+ <!-- Synthesize Trigger -->
1190
+ <button id="btn-generate" class="btn-generate">
1191
+ <span>⚑</span> Generate Speech
1192
+ </button>
1193
 
1194
+ <!-- Output Deck -->
1195
+ <div class="output-wrapper">
1196
+ <audio id="audio-element" style="display:none;"></audio>
1197
+
1198
+ <!-- Empty Placeholder -->
1199
+ <div id="output-empty-state" class="empty-placeholder">
1200
+ <span class="empty-icon">πŸŽ›οΈ</span>
1201
+ <span class="empty-text">Formulate a script above to voice speech</span>
1202
+ </div>
1203
+
1204
+ <!-- Elegant Audio Deck -->
1205
+ <div id="custom-player" class="audio-player" style="display: none;">
1206
+ <div class="visualizer-box">
1207
+ <div class="visualizer-wave">
1208
+ <span class="wave-bar"></span>
1209
+ <span class="wave-bar"></span>
1210
+ <span class="wave-bar"></span>
1211
+ <span class="wave-bar"></span>
1212
+ <span class="wave-bar"></span>
1213
+ <span class="wave-bar"></span>
1214
+ <span class="wave-bar"></span>
1215
+ <span class="wave-bar"></span>
1216
+ <span class="wave-bar"></span>
1217
+ <span class="wave-bar"></span>
1218
+ <span class="wave-bar"></span>
1219
+ <span class="wave-bar"></span>
1220
+ <span class="wave-bar"></span>
1221
+ <span class="wave-bar"></span>
1222
+ <span class="wave-bar"></span>
1223
+ <span class="wave-bar"></span>
1224
+ <span class="wave-bar"></span>
1225
+ <span class="wave-bar"></span>
1226
+ <span class="wave-bar"></span>
1227
+ <span class="wave-bar"></span>
1228
+ </div>
1229
+ </div>
1230
+
1231
+ <div class="player-row">
1232
+ <button type="button" id="player-play" class="btn-play">β–Ά</button>
1233
+ <div class="progress-box">
1234
+ <span id="player-current-time" class="time-lbl">00:00</span>
1235
+ <input type="range" id="player-progress" min="0" max="100" value="0">
1236
+ <span id="player-duration" class="time-lbl">00:00</span>
1237
+ </div>
1238
+ </div>
1239
 
1240
+ <div class="deck-footer">
1241
+ <!-- Volume -->
1242
+ <div class="vol-slider">
1243
+ <span class="vol-icon">πŸ”Š</span>
1244
+ <input type="range" id="player-volume" min="0" max="1" step="0.1" value="0.8">
1245
+ </div>
1246
+
1247
+ <!-- Speed control indicators -->
1248
+ <div class="speed-deck">
1249
+ <button type="button" class="btn-speed" data-speed="0.8">0.8x</button>
1250
+ <button type="button" class="btn-speed active" data-speed="1.0">1.0x</button>
1251
+ <button type="button" class="btn-speed" data-speed="1.2">1.2x</button>
1252
+ <button type="button" class="btn-speed" data-speed="1.5">1.5x</button>
1253
+ </div>
1254
+
1255
+ <!-- Downloader WAV -->
1256
+ <a id="player-download" class="btn-download-wav" href="#" download="dramabox_audio.wav">
1257
+ <span>πŸ“₯</span> Download
1258
+ </a>
1259
+ </div>
1260
+ </div>
1261
+ </div>
1262
+ </main>
1263
+
1264
+ <div class="ltx-banner" style="margin-top: 12px;">
1265
+ πŸ—οΈ&nbsp; Built on <a href="https://github.com/Lightricks/LTX-2" target="_blank">LTX-2</a> by
1266
+ <a href="https://huggingface.co/Lightricks" target="_blank">Lightricks</a>.
1267
+ <strong>DramaBox</strong> is <strong>Resemble AI's</strong> expressive TTS,
1268
+ trained on top of the LTX-2.3 audio branch under the LTX-2 Community License.
1269
+ Huge thanks to the Lightricks team for open-sourcing the base.
1270
+ </div>
1271
+
1272
+ <footer>
1273
+ &copy; 2026 DramaBox. Audio output watermarked with Resemble Perth.
1274
+ </footer>
1275
+ </div>
1276
+ </div>
1277
+
1278
+ </div>
1279
+
1280
+ <!-- Gradio API script module -->
1281
  <script type="module">
1282
  import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
1283
 
 
1377
  let selectedAudioFilename = "";
1378
 
1379
  // UI nodes
1380
+ const sidebar = document.getElementById("app-sidebar");
1381
+ const sidebarOverlay = document.getElementById("sidebar-overlay");
1382
+ const btnToggleSidebar = document.getElementById("btn-toggle-sidebar");
1383
+ const btnCloseSidebar = document.getElementById("btn-close-sidebar");
1384
+
1385
  const statusBox = document.getElementById("status-box");
1386
  const statusText = document.getElementById("status-text");
1387
  const btnGenerate = document.getElementById("btn-generate");
 
1390
  const dropzone = document.getElementById("dropzone");
1391
  const audioFileInput = document.getElementById("audio-file");
1392
 
 
 
 
 
 
1393
  // Settings sliders
1394
  const sliderCfg = document.getElementById("cfg");
1395
  const valCfg = document.getElementById("val-cfg");
 
1422
  const guideBody = document.getElementById("guide-body");
1423
  const guideArrow = document.getElementById("guide-arrow");
1424
 
1425
+ // --- Sidebar collapsers ---
1426
+ function toggleSidebar() {
1427
+ const isCollapsed = sidebar.classList.toggle("collapsed");
1428
+ sidebarOverlay.classList.toggle("active", !isCollapsed);
1429
+
1430
+ const btnText = btnToggleSidebar.querySelector(".toggle-text");
1431
+ btnText.innerText = isCollapsed ? "Show Control Deck & Demos" : "Hide Control Deck & Demos";
1432
+ }
1433
+
1434
+ btnToggleSidebar.addEventListener("click", toggleSidebar);
1435
+ btnCloseSidebar.addEventListener("click", toggleSidebar);
1436
+ sidebarOverlay.addEventListener("click", toggleSidebar);
1437
+
1438
+ // Collapse by default on load under 992px
1439
+ if (window.innerWidth <= 992) {
1440
+ sidebar.classList.add("collapsed");
1441
+ sidebarOverlay.classList.remove("active");
1442
+ } else {
1443
+ // Start open on desktop
1444
+ sidebar.classList.remove("collapsed");
1445
+ const btnText = btnToggleSidebar.querySelector(".toggle-text");
1446
+ btnText.innerText = "Hide Control Deck & Demos";
1447
+ }
1448
+
1449
  // Simple alert helper
1450
  function updateStatus(message, type = "info", showSpinner = true) {
1451
  statusBox.style.display = "flex";
 
1478
  }
1479
 
1480
  // Accordion animations
 
 
 
 
 
1481
  guideToggle.addEventListener("click", () => {
1482
  const isOpen = guideBody.classList.toggle("open");
1483
  guideArrow.innerText = isOpen ? "β–²" : "β–Ό";
 
1536
  <div class="file-capsule">
1537
  <div class="file-info">
1538
  <span>🎡</span>
1539
+ <span style="overflow: hidden; text-overflow: ellipsis; max-width: 190px;">${filename}</span>
1540
  </div>
1541
  <button type="button" class="btn-clear" id="btn-clear-upload" title="Remove voice file">βœ•</button>
1542
  </div>
 
1555
  <span class="upload-icon">πŸ“€</span>
1556
  <div class="upload-text">
1557
  <strong>Drop file</strong> or click to choose<br>
1558
+ <span>WAV, MP3, etc. (10s+)</span>
1559
  </div>
1560
  `;
1561
  }
 
1607
 
1608
  const filename = ex.voice.substring(ex.voice.lastIndexOf('/') + 1);
1609
  loadExampleVoice(ex.voice, filename);
1610
+
1611
+ // On mobile, automatically collapse sidebar when selecting a demo so they see the generator
1612
+ if (window.innerWidth <= 992) {
1613
+ toggleSidebar();
1614
+ }
1615
  });
1616
 
1617
  examplesContainer.appendChild(pill);
 
1713
 
1714
  try {
1715
  btnGenerate.disabled = true;
1716
+ btnGenerate.innerHTML = `<div class="alert-spinner"></div> Synthesizing...`;
1717
  updateStatus("Checking models & processing queues...", "info");
1718
 
1719
  let uploadedFileData = null;