akhaliq HF Staff commited on
Commit
7aef049
·
1 Parent(s): d504f24

Enlarge input & example media previews, add bottom-row preview wrappers, and switch examples fold to a light theme

Browse files
Files changed (1) hide show
  1. index.html +591 -177
index.html CHANGED
@@ -299,10 +299,6 @@
299
  display: none;
300
  }
301
 
302
- .viewport-center-trigger.output-mode .center-inline-preview {
303
- display: none;
304
- }
305
-
306
  /* Hide branding when output is showing */
307
  .viewport-bottom.output-hidden {
308
  opacity: 0;
@@ -359,67 +355,6 @@
359
  width: 100%;
360
  }
361
 
362
- /* Inline media attachment preview inside center prompt card */
363
- .center-inline-preview {
364
- display: none;
365
- width: 100%;
366
- border-radius: 10px;
367
- overflow: hidden;
368
- background: rgba(0, 0, 0, 0.25);
369
- border: 1px solid rgba(255, 255, 255, 0.08);
370
- position: relative;
371
- margin-bottom: 6px;
372
- }
373
-
374
- .center-inline-preview.visible {
375
- display: block;
376
- }
377
-
378
- .center-inline-preview-media {
379
- width: 100%;
380
- max-height: 220px;
381
- display: flex;
382
- align-items: center;
383
- justify-content: center;
384
- overflow: hidden;
385
- }
386
-
387
- .center-inline-preview-media img,
388
- .center-inline-preview-media video {
389
- width: 100%;
390
- max-height: 220px;
391
- object-fit: contain;
392
- }
393
-
394
- .center-inline-preview-remove {
395
- position: absolute;
396
- top: 8px;
397
- right: 8px;
398
- width: 26px;
399
- height: 26px;
400
- border-radius: 50%;
401
- background: rgba(0, 0, 0, 0.6);
402
- border: 1px solid rgba(255, 255, 255, 0.15);
403
- color: #fff;
404
- display: flex;
405
- align-items: center;
406
- justify-content: center;
407
- cursor: pointer;
408
- transition: var(--transition-fast);
409
- backdrop-filter: blur(8px);
410
- -webkit-backdrop-filter: blur(8px);
411
- }
412
-
413
- .center-inline-preview-remove:hover {
414
- background: rgba(239, 68, 68, 0.7);
415
- border-color: rgba(239, 68, 68, 0.5);
416
- }
417
-
418
- .center-inline-preview-remove i {
419
- width: 13px;
420
- height: 13px;
421
- }
422
-
423
  .center-prompt-body textarea.prompt-textarea {
424
  width: 100%;
425
  height: 44px;
@@ -518,21 +453,23 @@
518
  }
519
 
520
  .quick-example-pill {
521
- background: rgba(255, 255, 255, 0.02);
522
- border: 1px solid rgba(255, 255, 255, 0.04);
 
 
 
523
  backdrop-filter: blur(8px);
524
  -webkit-backdrop-filter: blur(8px);
525
  color: rgba(255, 255, 255, 0.65);
526
- padding: 6px 12px;
527
  border-radius: 100px;
528
  font-size: 12px;
529
  font-family: var(--font-inter);
530
  cursor: pointer;
531
  transition: var(--transition-fast);
532
- max-width: 180px;
533
  white-space: nowrap;
534
  overflow: hidden;
535
- text-overflow: ellipsis;
536
  }
537
 
538
  .quick-example-pill:hover {
@@ -542,6 +479,37 @@
542
  transform: translateY(-1px);
543
  }
544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  /* Bottom Section elements */
546
  .viewport-bottom {
547
  display: flex;
@@ -1521,6 +1489,282 @@
1521
  .examples-section-fold footer a:hover {
1522
  color: var(--accent-orange);
1523
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1524
  </style>
1525
  </head>
1526
  <body>
@@ -1541,6 +1785,14 @@
1541
  <div class="fs-bg-overlay"></div>
1542
  </div>
1543
 
 
 
 
 
 
 
 
 
1544
  <!-- FOLD 1: FLOATING CINEMATIC VIEWPORT LAYER -->
1545
  <div class="cinematic-viewport">
1546
 
@@ -1553,6 +1805,12 @@
1553
  <span class="brand-name">ByteDance</span>
1554
  </a>
1555
 
 
 
 
 
 
 
1556
  </header>
1557
 
1558
  <!-- Immersive Center Prompt Console -->
@@ -1562,22 +1820,32 @@
1562
  <span class="active-task-pill" id="center-task-badge">Text to Video</span>
1563
  </div>
1564
  <div class="center-prompt-body">
1565
- <!-- Inline media attachment preview -->
1566
- <div class="center-inline-preview" id="center-inline-preview">
1567
- <div class="center-inline-preview-media" id="center-inline-preview-media">
1568
- <!-- JS injects img/video here -->
 
 
 
 
 
 
 
 
 
1569
  </div>
1570
- <button class="center-inline-preview-remove" id="center-inline-preview-remove" title="Remove attachment">
1571
- <i data-lucide="x"></i>
1572
- </button>
1573
  </div>
1574
- <textarea class="prompt-textarea" id="prompt-input" placeholder="Describe what you want to generate..."></textarea>
1575
  </div>
1576
  <div class="center-prompt-footer">
1577
  <button class="center-options-btn" onclick="toggleSidebar()" title="Configure settings and inputs">
1578
  <i data-lucide="sliders"></i>
1579
  <span>Model Controls</span>
1580
  </button>
 
 
 
 
 
1581
  <button class="center-generate-btn" id="generate-trigger">
1582
  <i data-lucide="sparkles"></i>
1583
  <span>Generate</span>
@@ -1610,6 +1878,8 @@
1610
 
1611
  </div>
1612
 
 
 
1613
  <!-- SLIDE-OUT CONTROLS SIDEBAR -->
1614
  <div class="controls-sidebar" id="sidebar-controls-pane">
1615
  <div class="panel-title">
@@ -1622,8 +1892,8 @@
1622
  </button>
1623
  </div>
1624
 
1625
- <!-- Segmented Tab task selectors in sidebar -->
1626
- <div class="form-group">
1627
  <label class="form-label">Task family</label>
1628
  <div class="select-wrapper">
1629
  <select class="select-control" id="task-select-dropdown">
@@ -1756,6 +2026,9 @@
1756
  <div class="terminal-header">
1757
  <i data-lucide="terminal"></i> Response Output
1758
  </div>
 
 
 
1759
  <button class="copy-btn" id="copy-clipboard-btn" title="Copy response to clipboard">
1760
  <i data-lucide="copy"></i>
1761
  </button>
@@ -1800,11 +2073,7 @@
1800
  window.scrollTo({ top: 0, behavior: 'smooth' });
1801
  }
1802
 
1803
- function scrollToExamples() {
1804
- const examplesFold = document.getElementById("examples-wrapper-element");
1805
- examplesFold.style.display = "block";
1806
- examplesFold.scrollIntoView({ behavior: "smooth" });
1807
- }
1808
 
1809
  function toggleSidebar() {
1810
  const pane = document.getElementById("sidebar-controls-pane");
@@ -1877,6 +2146,20 @@
1877
  const cfgControl = document.getElementById("cfg-control");
1878
  const cfgVal = document.getElementById("cfg-val");
1879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1880
  // Trigger and status panel
1881
  const generateTrigger = document.getElementById("generate-trigger");
1882
  const statusCard = document.getElementById("status-card");
@@ -1923,15 +2206,42 @@
1923
  function initializeUI() {
1924
  if (!appConfig) return;
1925
 
1926
- // Generate Task dropdown items
1927
  taskSelectDropdown.innerHTML = "";
 
1928
  appConfig.TASK_CHOICES.forEach((taskLabel, idx) => {
1929
  const internalTask = appConfig.TASK_LABEL_TO_INTERNAL[taskLabel];
 
 
1930
  const opt = document.createElement("option");
1931
  opt.value = internalTask;
1932
  opt.textContent = taskLabel;
1933
  if (idx === 0) opt.selected = true;
1934
  taskSelectDropdown.appendChild(opt);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1935
  });
1936
 
1937
  // Bind click to task dropdown change
@@ -1992,10 +2302,11 @@
1992
  }
1993
  });
1994
 
1995
- // Bind Audio Volume toggles (mute/unmute generated full-screen video background)
1996
  bgVolumeToggle.addEventListener("click", () => {
1997
  videoMuted = !videoMuted;
1998
  bgVideoOutput.muted = videoMuted;
 
1999
 
2000
  if (videoMuted) {
2001
  bgVolumeToggle.innerHTML = '<i data-lucide="volume-x"></i>';
@@ -2021,6 +2332,22 @@
2021
  });
2022
  });
2023
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2024
  // Load initial task
2025
  if (taskSelectDropdown.options.length > 0) {
2026
  const opt = taskSelectDropdown.options[0];
@@ -2038,6 +2365,15 @@
2038
  taskSelectDropdown.value = activeTask;
2039
  }
2040
 
 
 
 
 
 
 
 
 
 
2041
  // Pulse highlight sidebar panel for feedback
2042
  sidebarControlsPane.classList.add("highlight-pulse");
2043
  setTimeout(() => sidebarControlsPane.classList.remove("highlight-pulse"), 1200);
@@ -2064,13 +2400,14 @@
2064
  promptInput.value = "";
2065
  }
2066
 
2067
- // Toggle Input Media upload visibility
2068
  const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
2069
  const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
2070
  const isVideoTask = activeTask === "video_edit" || activeTask === "x2t_video";
2071
 
2072
  if (isEdit || isUnderstanding) {
2073
  mediaUploadContainer.style.display = "block";
 
2074
  mediaFieldLabel.textContent = isVideoTask ? "Input Video" : "Input Image";
2075
 
2076
  // Customize drag-drop zone instructions
@@ -2082,6 +2419,7 @@
2082
  dragDropZone.style.display = "block";
2083
  } else {
2084
  mediaUploadContainer.style.display = "none";
 
2085
  dragDropZone.style.display = "none";
2086
  }
2087
 
@@ -2091,8 +2429,6 @@
2091
  // Populate examples
2092
  renderQuickExamples(activeTask);
2093
 
2094
- // Hide output displays back to initial placeholders
2095
- // resetOutputViewer();
2096
  }
2097
 
2098
  // --- Populate Resolutions, ratios, durations dynamically ---
@@ -2140,34 +2476,23 @@
2140
  }
2141
  }
2142
 
2143
- // --- Inline preview element caches ---
2144
- const centerInlinePreview = document.getElementById("center-inline-preview");
2145
- const centerInlinePreviewMedia = document.getElementById("center-inline-preview-media");
2146
- const centerInlinePreviewRemove = document.getElementById("center-inline-preview-remove");
2147
-
2148
- // Bind inline preview remove button
2149
- centerInlinePreviewRemove.addEventListener("click", () => clearSelectedFile());
2150
-
2151
- // --- Sync inline preview inside center prompt card ---
2152
- function updateCenterInlinePreview(src, type) {
2153
- centerInlinePreviewMedia.innerHTML = "";
2154
- if (!src) {
2155
- centerInlinePreview.classList.remove("visible");
2156
- return;
2157
- }
2158
- if (type === "video") {
2159
  const video = document.createElement("video");
2160
- video.src = src;
2161
  video.muted = true;
2162
  video.playsInline = true;
2163
- video.addEventListener("loadeddata", () => { video.currentTime = 0.5; });
2164
- centerInlinePreviewMedia.appendChild(video);
 
 
2165
  } else {
2166
  const img = document.createElement("img");
2167
- img.src = src;
2168
- centerInlinePreviewMedia.appendChild(img);
2169
  }
2170
- centerInlinePreview.classList.add("visible");
2171
  }
2172
 
2173
  // --- Handle Uploaded Files locally ---
@@ -2175,43 +2500,23 @@
2175
  if (!file) return;
2176
  selectedFile = file;
2177
 
2178
- // Display file details in preview card
 
 
 
2179
  previewFilename.textContent = selectedFile.name;
2180
- previewFilesize.textContent = `${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB`;
 
2181
 
2182
- // Build visual thumbnail preview
2183
- previewMediaWrapper.innerHTML = "";
2184
- const fileType = selectedFile.type;
2185
- const objectUrl = URL.createObjectURL(selectedFile);
2186
-
2187
- if (fileType.startsWith("image/")) {
2188
- const img = document.createElement("img");
2189
- img.src = objectUrl;
2190
- previewMediaWrapper.appendChild(img);
2191
- updateCenterInlinePreview(objectUrl, "image");
2192
- } else if (fileType.startsWith("video/")) {
2193
- const video = document.createElement("video");
2194
- video.src = objectUrl;
2195
- video.muted = true;
2196
- video.playsInline = true;
2197
- previewMediaWrapper.appendChild(video);
2198
-
2199
- // Seek to tiny frame to show video thumbnail
2200
- video.addEventListener("loadeddata", () => {
2201
- video.currentTime = 0.5;
2202
- });
2203
- updateCenterInlinePreview(objectUrl, "video");
2204
- } else {
2205
- const docIcon = document.createElement("div");
2206
- docIcon.style.color = "var(--text-secondary)";
2207
- docIcon.innerHTML = '<i data-lucide="file"></i>';
2208
- previewMediaWrapper.appendChild(docIcon);
2209
- lucide.createIcons();
2210
- updateCenterInlinePreview(null, null);
2211
- }
2212
 
 
2213
  dragDropZone.style.display = "none";
2214
  filePreviewCard.style.display = "flex";
 
2215
  uploadedFileReference = null;
2216
  }
2217
 
@@ -2220,7 +2525,10 @@
2220
  uploadedFileReference = null;
2221
  fileSelector.value = "";
2222
  filePreviewCard.style.display = "none";
2223
- updateCenterInlinePreview(null, null);
 
 
 
2224
 
2225
  const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
2226
  const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
@@ -2265,35 +2573,41 @@
2265
  const hasImage = exampleRow[4];
2266
 
2267
  if (hasVideo && (activeTask === "video_edit" || activeTask === "x2t_video")) {
2268
- previewFilename.textContent = hasVideo.split("/").pop();
 
 
 
2269
  previewFilesize.textContent = "Example Asset";
 
2270
 
2271
- previewMediaWrapper.innerHTML = "";
2272
- const video = document.createElement("video");
2273
- video.src = hasVideo;
2274
- video.muted = true;
2275
- video.playsInline = true;
2276
- previewMediaWrapper.appendChild(video);
2277
 
2278
  dragDropZone.style.display = "none";
2279
  filePreviewCard.style.display = "flex";
 
2280
 
2281
  uploadedFileReference = hasVideo;
2282
- updateCenterInlinePreview(hasVideo, "video");
2283
  } else if (hasImage && (activeTask === "image_edit" || activeTask === "x2t_image")) {
2284
- previewFilename.textContent = hasImage.split("/").pop();
 
 
 
2285
  previewFilesize.textContent = "Example Asset";
 
2286
 
2287
- previewMediaWrapper.innerHTML = "";
2288
- const img = document.createElement("img");
2289
- img.src = hasImage;
2290
- previewMediaWrapper.appendChild(img);
2291
 
2292
  dragDropZone.style.display = "none";
2293
  filePreviewCard.style.display = "flex";
 
2294
 
2295
  uploadedFileReference = hasImage;
2296
- updateCenterInlinePreview(hasImage, "image");
2297
  }
2298
 
2299
  // Trigger reset of viewer output
@@ -2337,8 +2651,51 @@
2337
 
2338
  const pill = document.createElement("button");
2339
  pill.className = "quick-example-pill";
2340
- pill.textContent = promptText;
2341
- pill.title = promptText;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2342
 
2343
  pill.addEventListener("click", () => {
2344
  populateExample(row);
@@ -2346,11 +2703,21 @@
2346
 
2347
  quickExamplesWrapper.appendChild(pill);
2348
  }
 
2349
  } else {
2350
  quickExamplesBox.style.display = "none";
2351
  }
2352
  }
2353
 
 
 
 
 
 
 
 
 
 
2354
  // --- Helper to calculate height/width based on Aspect Ratio ---
2355
  function calculateDimensions(aspectRatio, isImage) {
2356
  let width = 640;
@@ -2587,7 +2954,6 @@
2587
  if (typeof rawData === "string") {
2588
  parsed = JSON.parse(rawData);
2589
  } else if (typeof rawData === "object" && rawData !== null) {
2590
- // Already an object (in case Gradio deserializes it)
2591
  parsed = rawData;
2592
  } else {
2593
  console.warn("displayResult: Unexpected rawData type:", typeof rawData);
@@ -2607,13 +2973,6 @@
2607
  const textData = parsed.text || "";
2608
  const statusMsg = parsed.status || "";
2609
 
2610
- // Helper: resolve a file path to a servable URL
2611
- function resolveMediaUrl(filePath) {
2612
- if (!filePath || filePath.trim() === "") return null;
2613
- if (filePath.startsWith("http")) return filePath;
2614
- return "/api/file?path=" + encodeURIComponent(filePath);
2615
- }
2616
-
2617
  const videoUrl = resolveMediaUrl(videoPath);
2618
  const imageUrl = resolveMediaUrl(imagePath);
2619
  console.log("Resolved URLs:", { videoUrl, imageUrl, textData, statusMsg });
@@ -2624,27 +2983,41 @@
2624
  return;
2625
  }
2626
 
2627
- // Output Video generated: Takes up full-screen background
2628
  if (videoUrl) {
 
2629
  bgFallback.classList.remove("active");
2630
  bgImageOutput.classList.remove("active");
2631
  bgImageOutput.src = "";
2632
  bgLightboxTrigger.style.display = "none";
2633
 
2634
  bgVideoOutput.src = videoUrl;
2635
- bgVideoOutput.classList.add("active");
2636
- bgVideoOutput.muted = videoMuted;
2637
  bgVideoOutput.play();
2638
 
 
 
 
 
 
 
 
 
 
 
2639
  bgVolumeToggle.style.display = "flex";
2640
  bgDownloadLink.href = videoUrl;
2641
  outputActionsCard.style.display = "flex";
2642
  outputTextContainer.style.display = "none";
 
 
2643
  enterOutputMode();
2644
  console.log("Video output displayed:", videoUrl);
2645
  }
2646
- // Output Image generated: Takes up full-screen background
2647
  else if (imageUrl) {
 
2648
  bgFallback.classList.remove("active");
2649
  bgVideoOutput.classList.remove("active");
2650
  bgVideoOutput.removeAttribute("src");
@@ -2652,22 +3025,52 @@
2652
  bgVolumeToggle.style.display = "none";
2653
 
2654
  bgImageOutput.src = imageUrl;
2655
- bgImageOutput.classList.add("active");
2656
  bgLightboxTrigger.style.display = "flex";
2657
 
 
 
 
 
 
 
 
 
 
2658
  bgDownloadLink.href = imageUrl;
2659
  outputActionsCard.style.display = "flex";
2660
  outputTextContainer.style.display = "none";
 
 
2661
  enterOutputMode();
2662
  console.log("Image output displayed:", imageUrl);
2663
  }
2664
- // Output Text / Question answers: Rendered in styled overlay card on right
2665
  else if (textData) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2666
  outputTextContent.textContent = textData;
 
2667
  outputTextContainer.style.display = "block";
 
2668
  outputActionsCard.style.display = "none";
 
 
 
2669
  enterOutputMode();
2670
- console.log("Text output displayed:", textData);
2671
  } else {
2672
  console.warn("displayResult: No usable output found, resetting");
2673
  resetOutputViewer();
@@ -2676,23 +3079,34 @@
2676
 
2677
  // --- Helper to hide viewer outputs back to empty state ---
2678
  function resetOutputViewer() {
2679
- // Reset full-screen background elements back to fallback festival crowd
2680
  bgFallback.classList.add("active");
2681
 
2682
  bgImageOutput.classList.remove("active");
2683
  bgImageOutput.src = "";
 
2684
  bgLightboxTrigger.style.display = "none";
2685
 
2686
  bgVideoOutput.classList.remove("active");
2687
  bgVideoOutput.removeAttribute("src");
 
2688
  try { bgVideoOutput.load(); } catch (e) {}
2689
  bgVolumeToggle.style.display = "none";
2690
 
 
 
 
 
 
 
 
 
2691
  // Reset actions card and terminal
2692
  outputActionsCard.style.display = "none";
2693
  bgDownloadLink.href = "";
2694
 
2695
  outputTextContainer.style.display = "none";
 
2696
  outputTextContent.textContent = "";
2697
 
2698
  exitOutputMode();
 
299
  display: none;
300
  }
301
 
 
 
 
 
302
  /* Hide branding when output is showing */
303
  .viewport-bottom.output-hidden {
304
  opacity: 0;
 
355
  width: 100%;
356
  }
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  .center-prompt-body textarea.prompt-textarea {
359
  width: 100%;
360
  height: 44px;
 
453
  }
454
 
455
  .quick-example-pill {
456
+ display: inline-flex;
457
+ align-items: center;
458
+ gap: 6px;
459
+ background: rgba(255, 255, 255, 0.03);
460
+ border: 1px solid rgba(255, 255, 255, 0.05);
461
  backdrop-filter: blur(8px);
462
  -webkit-backdrop-filter: blur(8px);
463
  color: rgba(255, 255, 255, 0.65);
464
+ padding: 4px 12px 4px 6px;
465
  border-radius: 100px;
466
  font-size: 12px;
467
  font-family: var(--font-inter);
468
  cursor: pointer;
469
  transition: var(--transition-fast);
470
+ max-width: 260px;
471
  white-space: nowrap;
472
  overflow: hidden;
 
473
  }
474
 
475
  .quick-example-pill:hover {
 
479
  transform: translateY(-1px);
480
  }
481
 
482
+ .quick-example-thumb {
483
+ width: 20px;
484
+ height: 20px;
485
+ border-radius: 50%;
486
+ object-fit: cover;
487
+ border: 1px solid rgba(255, 255, 255, 0.15);
488
+ background: #000;
489
+ flex-shrink: 0;
490
+ }
491
+
492
+ .quick-example-thumb-icon {
493
+ display: inline-flex;
494
+ align-items: center;
495
+ justify-content: center;
496
+ width: 20px;
497
+ height: 20px;
498
+ border-radius: 50%;
499
+ background: rgba(249, 115, 22, 0.1);
500
+ border: 1px solid rgba(249, 115, 22, 0.2);
501
+ color: var(--accent-orange);
502
+ font-size: 9px;
503
+ flex-shrink: 0;
504
+ }
505
+
506
+ .quick-example-text {
507
+ white-space: nowrap;
508
+ overflow: hidden;
509
+ text-overflow: ellipsis;
510
+ display: inline-block;
511
+ }
512
+
513
  /* Bottom Section elements */
514
  .viewport-bottom {
515
  display: flex;
 
1489
  .examples-section-fold footer a:hover {
1490
  color: var(--accent-orange);
1491
  }
1492
+
1493
+ /* --- NEW PREMIUM UI CUSTOM STYLES --- */
1494
+
1495
+ /* Top Task Segmented Navigation Bar */
1496
+ .top-task-selector-container {
1497
+ position: absolute;
1498
+ top: 24px;
1499
+ left: 50%;
1500
+ transform: translateX(-50%);
1501
+ z-index: 100;
1502
+ display: flex;
1503
+ justify-content: center;
1504
+ align-items: center;
1505
+ max-width: 90vw;
1506
+ }
1507
+
1508
+ .top-task-nav-bar {
1509
+ background: rgba(10, 16, 32, 0.45);
1510
+ border: 1px solid var(--glass-border);
1511
+ backdrop-filter: blur(20px);
1512
+ -webkit-backdrop-filter: blur(20px);
1513
+ border-radius: 100px;
1514
+ padding: 4px;
1515
+ display: flex;
1516
+ gap: 4px;
1517
+ box-shadow: var(--shadow-premium);
1518
+ }
1519
+
1520
+ .task-nav-btn {
1521
+ background: transparent;
1522
+ border: none;
1523
+ color: var(--text-secondary);
1524
+ font-family: var(--font-outfit);
1525
+ font-weight: 600;
1526
+ font-size: 12.5px;
1527
+ padding: 7px 15px;
1528
+ border-radius: 100px;
1529
+ cursor: pointer;
1530
+ transition: var(--transition-fast);
1531
+ white-space: nowrap;
1532
+ display: flex;
1533
+ align-items: center;
1534
+ gap: 6px;
1535
+ }
1536
+
1537
+ .task-nav-btn:hover {
1538
+ color: #fff;
1539
+ background: rgba(255, 255, 255, 0.05);
1540
+ }
1541
+
1542
+ .task-nav-btn.active {
1543
+ background: var(--accent-gradient);
1544
+ color: #0f172a;
1545
+ box-shadow: 0 4px 12px rgba(249, 115, 22, 0.2);
1546
+ }
1547
+
1548
+ @media (max-width: 900px) {
1549
+ .top-task-selector-container {
1550
+ position: relative;
1551
+ top: 0;
1552
+ left: 0;
1553
+ transform: none;
1554
+ margin: 20px auto 10px;
1555
+ width: calc(100% - 40px);
1556
+ }
1557
+ .top-task-nav-bar {
1558
+ width: 100%;
1559
+ overflow-x: auto;
1560
+ justify-content: flex-start;
1561
+ padding: 6px;
1562
+ border-radius: 14px;
1563
+ -webkit-overflow-scrolling: touch;
1564
+ }
1565
+ .top-task-nav-bar::-webkit-scrollbar {
1566
+ display: none;
1567
+ }
1568
+ }
1569
+
1570
+ /* Input Media Preview inside Center Prompt Card */
1571
+ .input-media-preview {
1572
+ display: flex;
1573
+ flex-direction: column;
1574
+ background: rgba(255, 255, 255, 0.04);
1575
+ border: 1px solid rgba(255, 255, 255, 0.08);
1576
+ border-radius: 12px;
1577
+ padding: 8px;
1578
+ margin-top: 10px;
1579
+ gap: 8px;
1580
+ animation: slide-in 0.3s cubic-bezier(0.16, 1, 0.3, 1);
1581
+ }
1582
+
1583
+ .input-preview-thumbnail {
1584
+ width: 100%;
1585
+ height: 200px;
1586
+ border-radius: 8px;
1587
+ overflow: hidden;
1588
+ background: rgba(0, 0, 0, 0.3);
1589
+ display: flex;
1590
+ align-items: center;
1591
+ justify-content: center;
1592
+ border: 1px solid rgba(255, 255, 255, 0.1);
1593
+ }
1594
+
1595
+ .input-preview-thumbnail img,
1596
+ .input-preview-thumbnail video {
1597
+ width: 100%;
1598
+ height: 100%;
1599
+ object-fit: contain;
1600
+ }
1601
+
1602
+ .input-preview-bottom-row {
1603
+ display: flex;
1604
+ align-items: center;
1605
+ gap: 10px;
1606
+ }
1607
+
1608
+ .input-preview-info {
1609
+ display: flex;
1610
+ flex-direction: column;
1611
+ min-width: 0;
1612
+ flex-grow: 1;
1613
+ }
1614
+
1615
+ .input-preview-name {
1616
+ font-size: 13px;
1617
+ font-weight: 600;
1618
+ color: #fff;
1619
+ white-space: nowrap;
1620
+ overflow: hidden;
1621
+ text-overflow: ellipsis;
1622
+ }
1623
+
1624
+ .input-preview-size {
1625
+ font-size: 11px;
1626
+ color: var(--text-secondary);
1627
+ margin-top: 2px;
1628
+ }
1629
+
1630
+ .input-preview-clear {
1631
+ background: rgba(255, 255, 255, 0.04);
1632
+ border: 1px solid rgba(255, 255, 255, 0.08);
1633
+ color: var(--text-secondary);
1634
+ width: 28px;
1635
+ height: 28px;
1636
+ border-radius: 50%;
1637
+ cursor: pointer;
1638
+ display: flex;
1639
+ align-items: center;
1640
+ justify-content: center;
1641
+ transition: var(--transition-fast);
1642
+ flex-shrink: 0;
1643
+ }
1644
+
1645
+ .input-preview-clear:hover {
1646
+ background: rgba(239, 68, 68, 0.15);
1647
+ color: #ef4444;
1648
+ border-color: rgba(239, 68, 68, 0.3);
1649
+ }
1650
+
1651
+ .input-preview-clear i {
1652
+ width: 14px;
1653
+ height: 14px;
1654
+ }
1655
+
1656
+ /* Ambient Blur Backdrop Effect */
1657
+ .fs-bg-element.ambient-blur {
1658
+ filter: blur(50px) brightness(0.35);
1659
+ transform: scale(1.15);
1660
+ object-fit: cover;
1661
+ transition: opacity 0.8s ease-in-out;
1662
+ }
1663
+
1664
+ /* Centered Output Viewport Container */
1665
+ .centered-output-container {
1666
+ position: fixed;
1667
+ top: 48%;
1668
+ left: 50%;
1669
+ transform: translate(-50%, -50%);
1670
+ z-index: 5;
1671
+ display: none;
1672
+ justify-content: center;
1673
+ align-items: center;
1674
+ width: 80vw;
1675
+ height: 65vh;
1676
+ pointer-events: none;
1677
+ }
1678
+
1679
+ .centered-output-container.active {
1680
+ display: flex;
1681
+ animation: zoom-in-premium 0.5s cubic-bezier(0.16, 1, 0.3, 1);
1682
+ }
1683
+
1684
+ @keyframes zoom-in-premium {
1685
+ from { transform: translate(-50%, -48%) scale(0.95); opacity: 0; }
1686
+ to { transform: translate(-50%, -50%) scale(1); opacity: 1; }
1687
+ }
1688
+
1689
+ .output-media-card {
1690
+ background: rgba(15, 23, 42, 0.3);
1691
+ border: 1px solid rgba(255, 255, 255, 0.08);
1692
+ border-radius: 20px;
1693
+ padding: 10px;
1694
+ box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1);
1695
+ backdrop-filter: blur(16px);
1696
+ -webkit-backdrop-filter: blur(16px);
1697
+ max-width: 100%;
1698
+ max-height: 100%;
1699
+ display: flex;
1700
+ justify-content: center;
1701
+ align-items: center;
1702
+ pointer-events: auto;
1703
+ position: relative;
1704
+ overflow: hidden;
1705
+ }
1706
+
1707
+ .centered-media-element {
1708
+ max-width: 100%;
1709
+ max-height: 100%;
1710
+ width: auto;
1711
+ height: auto;
1712
+ object-fit: contain;
1713
+ border-radius: 12px;
1714
+ display: none;
1715
+ }
1716
+
1717
+ .centered-media-element.active {
1718
+ display: block;
1719
+ }
1720
+
1721
+ /* Large Centered Text Terminal styling */
1722
+ .terminal-container.centered-large {
1723
+ position: fixed;
1724
+ top: 50%;
1725
+ left: 50%;
1726
+ transform: translate(-50%, -50%);
1727
+ width: 90%;
1728
+ max-width: 800px;
1729
+ max-height: 60vh;
1730
+ margin: 0;
1731
+ z-index: 100;
1732
+ background: rgba(7, 10, 19, 0.85);
1733
+ border: 1px solid rgba(249, 115, 22, 0.3);
1734
+ box-shadow: 0 30px 60px rgba(0, 0, 0, 0.8), 0 0 30px rgba(249, 115, 22, 0.15);
1735
+ font-size: 15px;
1736
+ line-height: 1.7;
1737
+ padding: 28px;
1738
+ display: none;
1739
+ pointer-events: auto;
1740
+ }
1741
+
1742
+ .close-terminal-btn {
1743
+ position: absolute;
1744
+ top: 14px;
1745
+ right: 48px;
1746
+ background: rgba(255, 255, 255, 0.04);
1747
+ border: 1px solid var(--glass-border);
1748
+ color: var(--text-secondary);
1749
+ padding: 6px;
1750
+ border-radius: 6px;
1751
+ cursor: pointer;
1752
+ transition: var(--transition-fast);
1753
+ display: flex;
1754
+ align-items: center;
1755
+ justify-content: center;
1756
+ }
1757
+
1758
+ .close-terminal-btn:hover {
1759
+ background: rgba(239, 68, 68, 0.15);
1760
+ color: #ef4444;
1761
+ border-color: rgba(239, 68, 68, 0.3);
1762
+ }
1763
+
1764
+ .close-terminal-btn i {
1765
+ width: 14px;
1766
+ height: 14px;
1767
+ }
1768
  </style>
1769
  </head>
1770
  <body>
 
1785
  <div class="fs-bg-overlay"></div>
1786
  </div>
1787
 
1788
+ <!-- Centered Visual Output Viewport -->
1789
+ <div class="centered-output-container" id="centered-media-viewport">
1790
+ <div class="output-media-card">
1791
+ <img id="centered-image-output" class="centered-media-element" alt="Lance Generated Image Output">
1792
+ <video id="centered-video-output" class="centered-media-element" loop playsinline controls></video>
1793
+ </div>
1794
+ </div>
1795
+
1796
  <!-- FOLD 1: FLOATING CINEMATIC VIEWPORT LAYER -->
1797
  <div class="cinematic-viewport">
1798
 
 
1805
  <span class="brand-name">ByteDance</span>
1806
  </a>
1807
 
1808
+ <!-- Dynamic Top task switcher navigation -->
1809
+ <div class="top-task-selector-container">
1810
+ <div class="top-task-nav-bar" id="top-task-navbar">
1811
+ <!-- populated dynamically -->
1812
+ </div>
1813
+ </div>
1814
  </header>
1815
 
1816
  <!-- Immersive Center Prompt Console -->
 
1820
  <span class="active-task-pill" id="center-task-badge">Text to Video</span>
1821
  </div>
1822
  <div class="center-prompt-body">
1823
+ <textarea class="prompt-textarea" id="prompt-input" placeholder="Describe what you want to generate..."></textarea>
1824
+
1825
+ <!-- Media preview inside the input box -->
1826
+ <div class="input-media-preview" id="center-media-preview" style="display: none;">
1827
+ <div class="input-preview-thumbnail" id="center-preview-thumbnail"></div>
1828
+ <div class="input-preview-bottom-row">
1829
+ <div class="input-preview-info">
1830
+ <span class="input-preview-name" id="center-preview-name">file_name.mp4</span>
1831
+ <span class="input-preview-size" id="center-preview-size">0.0 MB</span>
1832
+ </div>
1833
+ <button class="input-preview-clear" id="center-preview-clear" title="Remove attachment">
1834
+ <i data-lucide="x"></i>
1835
+ </button>
1836
  </div>
 
 
 
1837
  </div>
 
1838
  </div>
1839
  <div class="center-prompt-footer">
1840
  <button class="center-options-btn" onclick="toggleSidebar()" title="Configure settings and inputs">
1841
  <i data-lucide="sliders"></i>
1842
  <span>Model Controls</span>
1843
  </button>
1844
+ <!-- Visual Input attach button for multimodal tasks -->
1845
+ <button class="center-options-btn" id="center-attach-btn" title="Attach input media (image or video)" style="display: none;">
1846
+ <i data-lucide="paperclip"></i>
1847
+ <span>Attach Media</span>
1848
+ </button>
1849
  <button class="center-generate-btn" id="generate-trigger">
1850
  <i data-lucide="sparkles"></i>
1851
  <span>Generate</span>
 
1878
 
1879
  </div>
1880
 
1881
+
1882
+
1883
  <!-- SLIDE-OUT CONTROLS SIDEBAR -->
1884
  <div class="controls-sidebar" id="sidebar-controls-pane">
1885
  <div class="panel-title">
 
1892
  </button>
1893
  </div>
1894
 
1895
+ <!-- Segmented Tab task selectors in sidebar (hidden, synced behind-the-scenes) -->
1896
+ <div class="form-group" style="display: none;">
1897
  <label class="form-label">Task family</label>
1898
  <div class="select-wrapper">
1899
  <select class="select-control" id="task-select-dropdown">
 
2026
  <div class="terminal-header">
2027
  <i data-lucide="terminal"></i> Response Output
2028
  </div>
2029
+ <button class="close-terminal-btn" id="close-terminal-trigger" title="Close response console">
2030
+ <i data-lucide="x"></i>
2031
+ </button>
2032
  <button class="copy-btn" id="copy-clipboard-btn" title="Copy response to clipboard">
2033
  <i data-lucide="copy"></i>
2034
  </button>
 
2073
  window.scrollTo({ top: 0, behavior: 'smooth' });
2074
  }
2075
 
2076
+
 
 
 
 
2077
 
2078
  function toggleSidebar() {
2079
  const pane = document.getElementById("sidebar-controls-pane");
 
2146
  const cfgControl = document.getElementById("cfg-control");
2147
  const cfgVal = document.getElementById("cfg-val");
2148
 
2149
+ // New Visual and Task Switcher Element Caches
2150
+ const topTaskNavbar = document.getElementById("top-task-navbar");
2151
+ const centerAttachBtn = document.getElementById("center-attach-btn");
2152
+ const centerMediaPreview = document.getElementById("center-media-preview");
2153
+ const centerPreviewThumbnail = document.getElementById("center-preview-thumbnail");
2154
+ const centerPreviewName = document.getElementById("center-preview-name");
2155
+ const centerPreviewSize = document.getElementById("center-preview-size");
2156
+ const centerPreviewClear = document.getElementById("center-preview-clear");
2157
+ const centeredMediaViewport = document.getElementById("centered-media-viewport");
2158
+ const centeredImageOutput = document.getElementById("centered-image-output");
2159
+ const centeredVideoOutput = document.getElementById("centered-video-output");
2160
+ const closeTerminalTrigger = document.getElementById("close-terminal-trigger");
2161
+
2162
+
2163
  // Trigger and status panel
2164
  const generateTrigger = document.getElementById("generate-trigger");
2165
  const statusCard = document.getElementById("status-card");
 
2206
  function initializeUI() {
2207
  if (!appConfig) return;
2208
 
2209
+ // Generate Task dropdown items and Top Segmented Nav Switcher
2210
  taskSelectDropdown.innerHTML = "";
2211
+ topTaskNavbar.innerHTML = "";
2212
  appConfig.TASK_CHOICES.forEach((taskLabel, idx) => {
2213
  const internalTask = appConfig.TASK_LABEL_TO_INTERNAL[taskLabel];
2214
+
2215
+ // Dropdown setup
2216
  const opt = document.createElement("option");
2217
  opt.value = internalTask;
2218
  opt.textContent = taskLabel;
2219
  if (idx === 0) opt.selected = true;
2220
  taskSelectDropdown.appendChild(opt);
2221
+
2222
+ // Top Segmented Pill Button setup
2223
+ const btn = document.createElement("button");
2224
+ btn.className = "task-nav-btn";
2225
+ btn.setAttribute("data-task", internalTask);
2226
+
2227
+ // Cohesive Lucide icons
2228
+ let iconName = "sparkles";
2229
+ if (internalTask === "t2v") iconName = "video";
2230
+ else if (internalTask === "t2i") iconName = "image";
2231
+ else if (internalTask === "video_edit") iconName = "film";
2232
+ else if (internalTask === "image_edit") iconName = "scissors";
2233
+ else if (internalTask === "x2t_video") iconName = "help-circle";
2234
+ else if (internalTask === "x2t_image") iconName = "help-circle";
2235
+
2236
+ btn.innerHTML = `<i data-lucide="${iconName}"></i><span>${taskLabel}</span>`;
2237
+ if (idx === 0) btn.classList.add("active");
2238
+
2239
+ btn.addEventListener("click", () => {
2240
+ document.querySelectorAll(".task-nav-btn").forEach(b => b.classList.remove("active"));
2241
+ btn.classList.add("active");
2242
+ switchTask(internalTask, taskLabel);
2243
+ });
2244
+ topTaskNavbar.appendChild(btn);
2245
  });
2246
 
2247
  // Bind click to task dropdown change
 
2302
  }
2303
  });
2304
 
2305
+ // Bind Audio Volume toggles (mute/unmute generated videos)
2306
  bgVolumeToggle.addEventListener("click", () => {
2307
  videoMuted = !videoMuted;
2308
  bgVideoOutput.muted = videoMuted;
2309
+ centeredVideoOutput.muted = videoMuted;
2310
 
2311
  if (videoMuted) {
2312
  bgVolumeToggle.innerHTML = '<i data-lucide="volume-x"></i>';
 
2332
  });
2333
  });
2334
 
2335
+ // Bind Visual attach button inside prompt box to target hidden file selector
2336
+ centerAttachBtn.addEventListener("click", () => {
2337
+ fileSelector.click();
2338
+ });
2339
+
2340
+ // Bind Clear button inside prompt box preview
2341
+ centerPreviewClear.addEventListener("click", (e) => {
2342
+ e.stopPropagation();
2343
+ clearSelectedFile();
2344
+ });
2345
+
2346
+ // Bind Close button inside centered large output terminal
2347
+ closeTerminalTrigger.addEventListener("click", () => {
2348
+ resetOutputViewer();
2349
+ });
2350
+
2351
  // Load initial task
2352
  if (taskSelectDropdown.options.length > 0) {
2353
  const opt = taskSelectDropdown.options[0];
 
2365
  taskSelectDropdown.value = activeTask;
2366
  }
2367
 
2368
+ // Sync top segmented navbar active button
2369
+ document.querySelectorAll(".task-nav-btn").forEach(btn => {
2370
+ if (btn.getAttribute("data-task") === activeTask) {
2371
+ btn.classList.add("active");
2372
+ } else {
2373
+ btn.classList.remove("active");
2374
+ }
2375
+ });
2376
+
2377
  // Pulse highlight sidebar panel for feedback
2378
  sidebarControlsPane.classList.add("highlight-pulse");
2379
  setTimeout(() => sidebarControlsPane.classList.remove("highlight-pulse"), 1200);
 
2400
  promptInput.value = "";
2401
  }
2402
 
2403
+ // Toggle Input Media upload visibility and Center Attach Button
2404
  const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
2405
  const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
2406
  const isVideoTask = activeTask === "video_edit" || activeTask === "x2t_video";
2407
 
2408
  if (isEdit || isUnderstanding) {
2409
  mediaUploadContainer.style.display = "block";
2410
+ centerAttachBtn.style.display = "flex";
2411
  mediaFieldLabel.textContent = isVideoTask ? "Input Video" : "Input Image";
2412
 
2413
  // Customize drag-drop zone instructions
 
2419
  dragDropZone.style.display = "block";
2420
  } else {
2421
  mediaUploadContainer.style.display = "none";
2422
+ centerAttachBtn.style.display = "none";
2423
  dragDropZone.style.display = "none";
2424
  }
2425
 
 
2429
  // Populate examples
2430
  renderQuickExamples(activeTask);
2431
 
 
 
2432
  }
2433
 
2434
  // --- Populate Resolutions, ratios, durations dynamically ---
 
2476
  }
2477
  }
2478
 
2479
+ // Helper to render thumbnails for either File objects or URL paths
2480
+ function renderThumbnail(wrapperElement, fileOrUrl, isVideoType) {
2481
+ wrapperElement.innerHTML = "";
2482
+ if (isVideoType) {
 
 
 
 
 
 
 
 
 
 
 
 
2483
  const video = document.createElement("video");
2484
+ video.src = typeof fileOrUrl === "string" ? fileOrUrl : URL.createObjectURL(fileOrUrl);
2485
  video.muted = true;
2486
  video.playsInline = true;
2487
+ wrapperElement.appendChild(video);
2488
+ video.addEventListener("loadeddata", () => {
2489
+ video.currentTime = 0.5;
2490
+ });
2491
  } else {
2492
  const img = document.createElement("img");
2493
+ img.src = typeof fileOrUrl === "string" ? fileOrUrl : URL.createObjectURL(fileOrUrl);
2494
+ wrapperElement.appendChild(img);
2495
  }
 
2496
  }
2497
 
2498
  // --- Handle Uploaded Files locally ---
 
2500
  if (!file) return;
2501
  selectedFile = file;
2502
 
2503
+ const sizeText = `${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB`;
2504
+ const isVideoType = selectedFile.type.startsWith("video/");
2505
+
2506
+ // 1. Update Controls Sidebar file details & thumbnail
2507
  previewFilename.textContent = selectedFile.name;
2508
+ previewFilesize.textContent = sizeText;
2509
+ renderThumbnail(previewMediaWrapper, selectedFile, isVideoType);
2510
 
2511
+ // 2. Update Center Prompt Card file details & thumbnail
2512
+ centerPreviewName.textContent = selectedFile.name;
2513
+ centerPreviewSize.textContent = sizeText;
2514
+ renderThumbnail(centerPreviewThumbnail, selectedFile, isVideoType);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2515
 
2516
+ // Toggle element visibilities
2517
  dragDropZone.style.display = "none";
2518
  filePreviewCard.style.display = "flex";
2519
+ centerMediaPreview.style.display = "flex";
2520
  uploadedFileReference = null;
2521
  }
2522
 
 
2525
  uploadedFileReference = null;
2526
  fileSelector.value = "";
2527
  filePreviewCard.style.display = "none";
2528
+ centerMediaPreview.style.display = "none";
2529
+
2530
+ previewMediaWrapper.innerHTML = "";
2531
+ centerPreviewThumbnail.innerHTML = "";
2532
 
2533
  const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
2534
  const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
 
2573
  const hasImage = exampleRow[4];
2574
 
2575
  if (hasVideo && (activeTask === "video_edit" || activeTask === "x2t_video")) {
2576
+ const filename = hasVideo.split("/").pop();
2577
+
2578
+ // 1. Sidebar Preview
2579
+ previewFilename.textContent = filename;
2580
  previewFilesize.textContent = "Example Asset";
2581
+ renderThumbnail(previewMediaWrapper, hasVideo, true);
2582
 
2583
+ // 2. Center Card Preview
2584
+ centerPreviewName.textContent = filename;
2585
+ centerPreviewSize.textContent = "Example Asset";
2586
+ renderThumbnail(centerPreviewThumbnail, hasVideo, true);
 
 
2587
 
2588
  dragDropZone.style.display = "none";
2589
  filePreviewCard.style.display = "flex";
2590
+ centerMediaPreview.style.display = "flex";
2591
 
2592
  uploadedFileReference = hasVideo;
 
2593
  } else if (hasImage && (activeTask === "image_edit" || activeTask === "x2t_image")) {
2594
+ const filename = hasImage.split("/").pop();
2595
+
2596
+ // 1. Sidebar Preview
2597
+ previewFilename.textContent = filename;
2598
  previewFilesize.textContent = "Example Asset";
2599
+ renderThumbnail(previewMediaWrapper, hasImage, false);
2600
 
2601
+ // 2. Center Card Preview
2602
+ centerPreviewName.textContent = filename;
2603
+ centerPreviewSize.textContent = "Example Asset";
2604
+ renderThumbnail(centerPreviewThumbnail, hasImage, false);
2605
 
2606
  dragDropZone.style.display = "none";
2607
  filePreviewCard.style.display = "flex";
2608
+ centerMediaPreview.style.display = "flex";
2609
 
2610
  uploadedFileReference = hasImage;
 
2611
  }
2612
 
2613
  // Trigger reset of viewer output
 
2651
 
2652
  const pill = document.createElement("button");
2653
  pill.className = "quick-example-pill";
2654
+
2655
+ // Resolve visual preview URL (Index 1/2 for video, Index 3/4 for image)
2656
+ const isVideoType = (task === "t2v" || task === "video_edit" || task === "x2t_video");
2657
+ let mediaUrl = isVideoType ? resolveMediaUrl(row[1] || row[2]) : resolveMediaUrl(row[3] || row[4]);
2658
+
2659
+ if (mediaUrl) {
2660
+ if (isVideoType) {
2661
+ const thumbVideo = document.createElement("video");
2662
+ thumbVideo.src = mediaUrl;
2663
+ thumbVideo.className = "quick-example-thumb";
2664
+ thumbVideo.muted = true;
2665
+ thumbVideo.playsInline = true;
2666
+
2667
+ // Micro-animation: Hover to play tiny video thumbnail
2668
+ pill.addEventListener("mouseenter", () => {
2669
+ thumbVideo.play().catch(() => {});
2670
+ });
2671
+ pill.addEventListener("mouseleave", () => {
2672
+ thumbVideo.pause();
2673
+ thumbVideo.currentTime = 0.5;
2674
+ });
2675
+
2676
+ pill.appendChild(thumbVideo);
2677
+ thumbVideo.addEventListener("loadeddata", () => {
2678
+ thumbVideo.currentTime = 0.5;
2679
+ });
2680
+ } else {
2681
+ const thumbImg = document.createElement("img");
2682
+ thumbImg.src = mediaUrl;
2683
+ thumbImg.className = "quick-example-thumb";
2684
+ pill.appendChild(thumbImg);
2685
+ }
2686
+ } else {
2687
+ const fallbackIcon = document.createElement("div");
2688
+ fallbackIcon.className = "quick-example-thumb-icon";
2689
+ fallbackIcon.innerHTML = '<i data-lucide="sparkles" style="width:10px;height:10px;"></i>';
2690
+ pill.appendChild(fallbackIcon);
2691
+ }
2692
+
2693
+ // Add text element
2694
+ const textSpan = document.createElement("span");
2695
+ textSpan.className = "quick-example-text";
2696
+ textSpan.textContent = promptText;
2697
+ textSpan.title = promptText;
2698
+ pill.appendChild(textSpan);
2699
 
2700
  pill.addEventListener("click", () => {
2701
  populateExample(row);
 
2703
 
2704
  quickExamplesWrapper.appendChild(pill);
2705
  }
2706
+ lucide.createIcons();
2707
  } else {
2708
  quickExamplesBox.style.display = "none";
2709
  }
2710
  }
2711
 
2712
+ // Global Helper: resolve a file path to a servable URL
2713
+ function resolveMediaUrl(filePath) {
2714
+ if (!filePath || filePath.trim() === "") return null;
2715
+ if (filePath.startsWith("http")) return filePath;
2716
+ return "/api/file?path=" + encodeURIComponent(filePath);
2717
+ }
2718
+
2719
+
2720
+
2721
  // --- Helper to calculate height/width based on Aspect Ratio ---
2722
  function calculateDimensions(aspectRatio, isImage) {
2723
  let width = 640;
 
2954
  if (typeof rawData === "string") {
2955
  parsed = JSON.parse(rawData);
2956
  } else if (typeof rawData === "object" && rawData !== null) {
 
2957
  parsed = rawData;
2958
  } else {
2959
  console.warn("displayResult: Unexpected rawData type:", typeof rawData);
 
2973
  const textData = parsed.text || "";
2974
  const statusMsg = parsed.status || "";
2975
 
 
 
 
 
 
 
 
2976
  const videoUrl = resolveMediaUrl(videoPath);
2977
  const imageUrl = resolveMediaUrl(imagePath);
2978
  console.log("Resolved URLs:", { videoUrl, imageUrl, textData, statusMsg });
 
2983
  return;
2984
  }
2985
 
2986
+ // Output Video generated: Takes up full-screen background as ambient blur + centered sharp preview
2987
  if (videoUrl) {
2988
+ // 1. Ambient Blur Backdrop
2989
  bgFallback.classList.remove("active");
2990
  bgImageOutput.classList.remove("active");
2991
  bgImageOutput.src = "";
2992
  bgLightboxTrigger.style.display = "none";
2993
 
2994
  bgVideoOutput.src = videoUrl;
2995
+ bgVideoOutput.className = "fs-bg-element fs-bg-video ambient-blur active";
2996
+ bgVideoOutput.muted = true; // ambient blur backdrop is always silent
2997
  bgVideoOutput.play();
2998
 
2999
+ // 2. Centered Sharp Foreground
3000
+ centeredMediaViewport.classList.add("active");
3001
+ centeredImageOutput.classList.remove("active");
3002
+ centeredImageOutput.src = "";
3003
+
3004
+ centeredVideoOutput.src = videoUrl;
3005
+ centeredVideoOutput.classList.add("active");
3006
+ centeredVideoOutput.muted = videoMuted;
3007
+ centeredVideoOutput.play();
3008
+
3009
  bgVolumeToggle.style.display = "flex";
3010
  bgDownloadLink.href = videoUrl;
3011
  outputActionsCard.style.display = "flex";
3012
  outputTextContainer.style.display = "none";
3013
+ outputTextContainer.classList.remove("centered-large");
3014
+
3015
  enterOutputMode();
3016
  console.log("Video output displayed:", videoUrl);
3017
  }
3018
+ // Output Image generated: Takes up full-screen background as ambient blur + centered sharp preview
3019
  else if (imageUrl) {
3020
+ // 1. Ambient Blur Backdrop
3021
  bgFallback.classList.remove("active");
3022
  bgVideoOutput.classList.remove("active");
3023
  bgVideoOutput.removeAttribute("src");
 
3025
  bgVolumeToggle.style.display = "none";
3026
 
3027
  bgImageOutput.src = imageUrl;
3028
+ bgImageOutput.className = "fs-bg-element ambient-blur active";
3029
  bgLightboxTrigger.style.display = "flex";
3030
 
3031
+ // 2. Centered Sharp Foreground
3032
+ centeredMediaViewport.classList.add("active");
3033
+ centeredVideoOutput.classList.remove("active");
3034
+ centeredVideoOutput.removeAttribute("src");
3035
+ try { centeredVideoOutput.load(); } catch (e) {}
3036
+
3037
+ centeredImageOutput.src = imageUrl;
3038
+ centeredImageOutput.classList.add("active");
3039
+
3040
  bgDownloadLink.href = imageUrl;
3041
  outputActionsCard.style.display = "flex";
3042
  outputTextContainer.style.display = "none";
3043
+ outputTextContainer.classList.remove("centered-large");
3044
+
3045
  enterOutputMode();
3046
  console.log("Image output displayed:", imageUrl);
3047
  }
3048
+ // Output Text / Question answers: Rendered in enlarged centered panel
3049
  else if (textData) {
3050
+ // Reset visual backgrounds
3051
+ bgFallback.classList.add("active");
3052
+ bgImageOutput.classList.remove("active");
3053
+ bgImageOutput.src = "";
3054
+ bgVideoOutput.classList.remove("active");
3055
+ bgVideoOutput.removeAttribute("src");
3056
+ try { bgVideoOutput.load(); } catch (e) {}
3057
+
3058
+ centeredMediaViewport.classList.remove("active");
3059
+ centeredImageOutput.classList.remove("active");
3060
+ centeredImageOutput.src = "";
3061
+ centeredVideoOutput.classList.remove("active");
3062
+ centeredVideoOutput.removeAttribute("src");
3063
+
3064
  outputTextContent.textContent = textData;
3065
+ outputTextContainer.classList.add("centered-large");
3066
  outputTextContainer.style.display = "block";
3067
+
3068
  outputActionsCard.style.display = "none";
3069
+ bgLightboxTrigger.style.display = "none";
3070
+ bgVolumeToggle.style.display = "none";
3071
+
3072
  enterOutputMode();
3073
+ console.log("Text output displayed centered:", textData);
3074
  } else {
3075
  console.warn("displayResult: No usable output found, resetting");
3076
  resetOutputViewer();
 
3079
 
3080
  // --- Helper to hide viewer outputs back to empty state ---
3081
  function resetOutputViewer() {
3082
+ // Reset full-screen background elements back to fallback
3083
  bgFallback.classList.add("active");
3084
 
3085
  bgImageOutput.classList.remove("active");
3086
  bgImageOutput.src = "";
3087
+ bgImageOutput.className = "fs-bg-element";
3088
  bgLightboxTrigger.style.display = "none";
3089
 
3090
  bgVideoOutput.classList.remove("active");
3091
  bgVideoOutput.removeAttribute("src");
3092
+ bgVideoOutput.className = "fs-bg-element fs-bg-video";
3093
  try { bgVideoOutput.load(); } catch (e) {}
3094
  bgVolumeToggle.style.display = "none";
3095
 
3096
+ // Reset centered outputs
3097
+ centeredMediaViewport.classList.remove("active");
3098
+ centeredImageOutput.classList.remove("active");
3099
+ centeredImageOutput.src = "";
3100
+ centeredVideoOutput.classList.remove("active");
3101
+ centeredVideoOutput.removeAttribute("src");
3102
+ try { centeredVideoOutput.load(); } catch (e) {}
3103
+
3104
  // Reset actions card and terminal
3105
  outputActionsCard.style.display = "none";
3106
  bgDownloadLink.href = "";
3107
 
3108
  outputTextContainer.style.display = "none";
3109
+ outputTextContainer.classList.remove("centered-large");
3110
  outputTextContent.textContent = "";
3111
 
3112
  exitOutputMode();