| 419 | } |
| 420 | |
| 421 | function analysisBody() { |
| 422 | const a = state.current?.detail?.analysis; |
| 423 | const hasVideo = state.current?.detail?.hasVideo; |
| 424 | const statsHtml = a && a.stats.length |
| 425 | ? `<div class="stats">${a.stats.map((x) => `<div class="stat"><div class="stat-k">${x.k}</div><div class="stat-v">${esc(x.v)}</div><div class="stat-s">${esc(x.s)}</div></div>`).join("")}</div>` |
| 426 | : `<div class="lib-note" style="margin-top:8px">Analysis not available for this track.</div>`; |
| 427 | const presenceHtml = a && a.presence.length |
| 428 | ? `<div class="eyebrow">STEM PRESENCE</div>${a.presence.map((p) => `<div class="presence-row"><div class="presence-name">${esc(p.name)}</div><div class="presence-bar"><i style="width:${p.val}%;background:${p.color}"></i></div><span class="presence-val">${p.val}%</span></div>`).join("")}` |
| 429 | : ""; |
| 430 | const exportBtns = `<button class="cta sm" data-action="export" data-kind="wav">${ICON.download}Export mix</button>${ |
| 431 | hasVideo ? `<button class="cta sm" data-action="export" data-kind="mp4" style="margin-top:10px">${ICON.download}Export MP4 (with video)</button>` : "" |
| 432 | }`; |
| 433 | return `<div class="pad" style="padding-top:16px">${statsHtml}${presenceHtml}${exportBtns}</div>`; |
| 434 | } |
| 435 | |
| 436 | function mixerScreen() { |
| 437 | const c = state.current || { title: "No track selected", sub: "Pick one from your Library", initial: "♪", gradient: DEFAULT_GRADIENT, stemCount: 0 }; |