1/* minutes â animated live multilingual transcript 2 Streams source lines, then lands translations a beat later. 3 Persian (fa) renders right-to-left. Loops; respects reduced-motion. */ 4(function () { 5 const LINES = [ 6 { 7 who: "Anna Vogel", t: "09:32", 8 lang: "DE", dir: "ltr", 9 src: "Sollen wir mit den Quartalszahlen anfangen?", 10 tr: { lang: "EN", dir: "ltr", text: "Shall we start with the quarterly figures?" }, 11 }, 12 { 13 who: "Darius Ahmadi", t: "09:32", 14 lang: "FA", dir: "rtl", 15 src: "بÙÙØ Ù Ù Ø®ÙØ§ØµÙ را از ÙØ¨Ù آ٠اد٠کردÙâØ§Ù .", 16 tr: { lang: "EN", dir: "ltr", text: "Yes, I've already prepared the summary." }, 17 }, 18 { 19 who: "James Okoro", t: "09:33", 20 lang: "EN", dir: "ltr", 21 src: "Great â can you walk us through the revenue?", 22 tr: { lang: "DE", dir: "ltr", text: "Super â kannst du uns durch den Umsatz führen?" }, 23 }, 24 { 25 who: "Anna Vogel", t: "09:33", 26 lang: "DE", dir: "ltr", 27 src: "Der Umsatz ist um 18 % gestiegen.", 28 tr: { lang: "EN", dir: "ltr", text: "Revenue grew by 18%." }, 29 }, 30 { 31 who: "Darius Ahmadi", t: "09:34", 32 lang: "FA", dir: "rtl", 33 src: "ÙØ²ÛÙÙâÙØ§ ÙÙ ØªØØª Ú©ÙØªØ±Ù باÙÛ Ù Ø§ÙØ¯.", 34 tr: { lang: "EN", dir: "ltr", text: "Costs also stayed under control." }, 35 }, 36 ]; 37 38 function el(tag, cls, html) { 39 const n = document.createElement(tag); 40 if (cls) n.className = cls; 41 if (html != null) n.innerHTML = html; 42 return n; 43 } 44 45 function buildLine(d) { 46 const row = el("div", "tline"); 47 row.dataset.lang = d.lang; 48 49 const meta = el("div", "tline__meta"); 50 meta.appendChild(el("span", "tline__who", d.who)); 51 meta.appendChild(el("span", "tline__time fs-mono", d.t)); 52 row.appendChild(meta); 53 54 const src = el("div", "tline__src"); 55 src.dir = d.dir; 56 const tag = el("span", "tline__lang fs-mono", d.lang); 57 const txt = el("span", "tline__text", d.src); 58 if (d.dir === "rtl") { src.appendChild(txt); src.appendChild(tag); } 59 else { src.appendChild(tag); src.appendChild(txt); } 60 row.appendChild(src); 61 62 const tr = el("div", "tline__tr"); 63 tr.dir = d.tr.dir; 64 const ti = el("span", "tline__tricon fs-mono", "â " + d.tr.lang); 65 const tt = el("span", "tline__text", d.tr.text); 66 tr.appendChild(ti); 67 tr.appendChild(tt); 68 row.appendChild(tr); 69 70 return row; 71 } 72 73 function init() { 74 const stream = document.getElementById("transcript-stream"); 75 if (!stream) return; 76 const interim = document.getElementById("transcript-interim"); 77 const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; 78
79 function renderStatic() { 80 stream.innerHTML = ""; 81 LINES.forEach((d) => { 82 const row = buildLine(d); 83 row.classList.add("is-in"); 84 row.querySelector(".tline__tr").classList.add("is-in"); 85 stream.appendChild(row); 86 }); 87 if (interim) interim.style.opacity = "0"; 88 } 89 90 if (reduce || window.__minutesTranscriptMotion === false) { 91 renderStatic(); 92 return; 93 } 94 95 let timers = []; 96 function clear() { timers.forEach(clearTimeout); timers = []; } 97 function at(ms, fn) { timers.push(setTimeout(fn, ms)); } 98 99 function run() { 100 clear(); 101 stream.innerHTML = ""; 102 if (interim) interim.style.opacity = "0"; 103 104 let clock = 300; 105 const SRC_GAP = 1150; 106 const TR_DELAY = 520; 107 108 LINES.forEach((d) => { 109 const row = buildLine(d); 110 stream.appendChild(row); 111 const appearAt = clock; 112 at(appearAt, () => { 113 row.classList.add("is-in"); 114 if (interim) { 115 interim.style.opacity = "1"; 116 const ip = interim.querySelector(".tinterim__text"); 117 if (ip) ip.textContent = "transcribingâ¦"; 118 } 119 stream.scrollTo({ top: stream.scrollHeight, behavior: "smooth" }); 120 }); 121 at(appearAt + TR_DELAY, () => { 122 row.querySelector(".tline__tr").classList.add("is-in"); 123 stream.scrollTo({ top: stream.scrollHeight, behavior: "smooth" }); 124 }); 125 clock += SRC_GAP; 126 }); 127 128 at(clock + 1400, () => { 129 if (interim) { 130 interim.style.opacity = "1"; 131 const ip = interim.querySelector(".tinterim__text"); 132 if (ip) ip.textContent = "listeningâ¦"; 133 } 134 }); 135 at(clock + 3200, run); 136 } 137 138 window.__restartTranscript = function () { 139 clear(); 140 if (window.__minutesTranscriptMotion === false) renderStatic(); 141 else run(); 142 }; 143 144 run(); 145 } 146 147 if (document.readyState === "loading") { 148 document.addEventListener("DOMContentLoaded", init); 149 } else { 150 init(); 151 } 152})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.