// ── Output Example Demo renderer ─────────────────────────────────────────────
// Supports multiple clips with left/right arrow navigation, device selector,
// and streaming text effect at real TPS speed.
const DEMO_DEVICE_LABELS = {
orin_nano_super: "Jetson Orin Nano Super",
agx_orin: "Jetson AGX Orin",
agx_thor: "Jetson AGX Thor",
};
const DEMO_DEFAULT_DEVICE = "agx_orin";
const DEMO_TOKENS_PER_WORD = 1.33;
// ── CSV parser (minimal, demo-only) ─────────────────────────────────────────
function demoParseCsv(text) {
const lines = text.replace(/\r/g, "").trim().split("\n");
const headers = lines[0].split(",");
return lines.slice(1).map(line => {
const vals = line.split(",");
const row = {};
headers.forEach((h, i) => { row[h] = (vals[i] || "").trim(); });
return row;
});
}
// ── Look up TPS from benchmark data ─────────────────────────────────────────
function demoLookupTps(csvRows, modelName, device, matchCriteria) {
const row = csvRows.find(r =>
r.model === modelName &&
r.device === device &&
Object.entries(matchCriteria).every(([col, val]) => r[col] === val)
);
if (row) {
if (!row.tps || row.tps.toUpperCase() === "OOM") return { found: true, tps: null };
return { found: true, tps: parseFloat(row.tps) };
}
const oomRow = csvRows.find(r =>
r.model === modelName &&
r.device === device &&
r.tps && r.tps.toUpperCase() === "OOM"
);
if (oomRow) return { found: true, tps: null };
return { found: false, tps: null };
}
// ── Determine available devices from benchmark data ─────────────────────────
function demoAvailableDevices(csvRows, models, matchCriteria) {
const deviceSet = new Set();
csvRows.forEach(r => {
if (!models.includes(r.model)) return;
if (!Object.entries(matchCriteria).every(([col, val]) => r[col] === val)) return;
if (r.tps && r.tps.toUpperCase() !== "OOM") deviceSet.add(r.device);
});
return Object.keys(DEMO_DEVICE_LABELS).filter(d => deviceSet.has(d));
}
// ── Streaming text animation ────────────────────────────────────────────────
function demoStreamText(element, fullText, tps) {
const handle = { _tid: null, cancel() { clearTimeout(this._tid); } };
element.textContent = "";
if (!tps || tps <= 0) {
element.textContent = fullText;
return handle;
}
const words = fullText.split(/(\s+)/);
const delayMs = 1000 / (tps / DEMO_TOKENS_PER_WORD);
let idx = 0;
function tick() {
if (idx < words.length) {
element.textContent += words[idx];
idx++;
handle._tid = setTimeout(tick, delayMs);
}
}
tick();
return handle;
}
// ── Pre-calculate height for an output box to prevent layout shift ──────────
function demoPreCalcHeight(box, textEl, fullText) {
textEl.textContent = fullText;
const h = box.offsetHeight;
box.style.minHeight = h + "px";
textEl.textContent = "";
}
// ── Main render function ────────────────────────────────────────────────────
async function renderDemo(data, container, optimizedOrg, dataFile, modelColors) {
if (!data) return;
// Normalise: support both old single-clip format and new clips array
let clips = data.clips;
if (!clips) {
clips = [{
video: data.video,
label: data.title,
prompt: data.prompt,
inference_setup: data.inference_setup,
citation: data.citation,
citation_url: data.citation_url,
outputs: data.outputs,
}];
}
if (!clips.length) return;
const matchCriteria = data.benchmark_match || {};
// Collect all model names across clips
const allModelNames = [...new Set(clips.flatMap(c => (c.outputs || []).map(o => o.model)))];
// Load benchmark CSV
let csvRows = [];
if (dataFile) {
try {
const csvResp = await fetch(dataFile);
if (csvResp.ok) csvRows = demoParseCsv(await csvResp.text());
} catch { /* proceed without */ }
}
const devices = csvRows.length
? demoAvailableDevices(csvRows, allModelNames, matchCriteria)
: [];
let selectedDevice = devices.includes(DEMO_DEFAULT_DEVICE)
? DEMO_DEFAULT_DEVICE
: (devices[0] || DEMO_DEFAULT_DEVICE);
let currentClipIdx = 0;
let activeStreams = [];
// ── Build DOM skeleton ──────────────────────────────────────────────
const section = document.createElement("div");
section.className = "demo-section";
// Toggle button
const toggle = document.createElement("button");
toggle.className = "demo-toggle";
toggle.innerHTML = '▶ Show Demo';
// Collapsible wrapper
const content = document.createElement("div");
content.className = "demo-content";
const inner = document.createElement("div");
inner.className = "demo-content-inner";
const card = document.createElement("div");
card.className = "demo-card";
// Title row: h3 + device selector
const titleRow = document.createElement("div");
titleRow.className = "demo-title-row";
const titleLeft = document.createElement("div");
titleLeft.className = "demo-title-left";
const h3 = document.createElement("h3");
titleLeft.appendChild(h3);
const clipSetup = document.createElement("span");
clipSetup.className = "demo-clip-setup";
titleLeft.appendChild(clipSetup);
titleRow.appendChild(titleLeft);
const deviceSelector = document.createElement("div");
deviceSelector.className = "demo-device-selector";
if (devices.length > 1) {
const deviceGroup = document.createElement("div");
deviceGroup.className = "btn-group";
function renderDeviceButtons() {
deviceGroup.innerHTML = "";
devices.forEach(dev => {
const btn = document.createElement("button");
btn.className = "btn" + (dev === selectedDevice ? " active" : "");
btn.dataset.value = dev;
btn.textContent = DEMO_DEVICE_LABELS[dev] || dev;
deviceGroup.appendChild(btn);
});
}
renderDeviceButtons();
deviceGroup.addEventListener("click", e => {
const btn = e.target.closest(".btn");
if (!btn) return;
const newDevice = btn.dataset.value;
if (newDevice === selectedDevice) return;
selectedDevice = newDevice;
renderDeviceButtons();
renderOutputs();
});
deviceSelector.appendChild(deviceGroup);
}
card.appendChild(titleRow);
// Video with overlay arrows
const videoWrap = document.createElement("div");
videoWrap.className = "demo-video-wrap";
function makeVideoEl() {
const v = document.createElement("video");
v.loop = true;
v.muted = true;
v.playsInline = true;
v.preload = "auto";
v.className = "demo-video";
return v;
}
let videoA = makeVideoEl();
let videoB = makeVideoEl();
videoB.style.opacity = "0";
videoWrap.appendChild(videoA);
videoWrap.appendChild(videoB);
const arrowLeft = document.createElement("button");
arrowLeft.className = "demo-arrow demo-arrow-left";
arrowLeft.innerHTML = "◀";
arrowLeft.setAttribute("aria-label", "Previous clip");
const arrowRight = document.createElement("button");
arrowRight.className = "demo-arrow demo-arrow-right";
arrowRight.innerHTML = "▶";
arrowRight.setAttribute("aria-label", "Next clip");
videoWrap.appendChild(arrowLeft);
videoWrap.appendChild(arrowRight);
card.appendChild(videoWrap);
let isFirstClip = true;
// Device selector (centered under video)
card.appendChild(deviceSelector);
// Prompt (full width)
const promptEl = document.createElement("div");
promptEl.className = "demo-prompt";
card.appendChild(promptEl);
// Outputs grid
const grid = document.createElement("div");
grid.className = "demo-outputs";
card.appendChild(grid);
// Citation
const citeEl = document.createElement("p");
citeEl.className = "demo-citation";
card.appendChild(citeEl);
// ── Arrow visibility ────────────────────────────────────────────────
function updateArrows() {
const showArrows = clips.length > 1;
arrowLeft.style.display = showArrows ? "" : "none";
arrowRight.style.display = showArrows ? "" : "none";
arrowLeft.disabled = false;
arrowRight.disabled = false;
}
arrowLeft.addEventListener("click", () => {
currentClipIdx = (currentClipIdx - 1 + clips.length) % clips.length;
renderClip();
});
arrowRight.addEventListener("click", () => {
currentClipIdx = (currentClipIdx + 1) % clips.length;
renderClip();
});
// ── Render current clip ─────────────────────────────────────────────
function cancelStreams() {
activeStreams.forEach(s => s.cancel());
activeStreams = [];
}
function renderOutputs() {
cancelStreams();
grid.innerHTML = "";
const clip = clips[currentClipIdx];
const outputs = clip.outputs || [];
outputs.forEach(out => {
const color = modelColors && modelColors[out.model];
const borderColor = color ? color.border : null;
const box = document.createElement("div");
box.className = "demo-output";
if (borderColor) box.style.borderColor = borderColor;
const modelEl = document.createElement("span");
modelEl.className = "demo-output-model";
modelEl.textContent = out.model;
if (borderColor) modelEl.style.color = borderColor;
box.appendChild(modelEl);
const tpsEl = document.createElement("span");
tpsEl.className = "demo-output-tps";
if (borderColor) tpsEl.style.color = borderColor;
box.appendChild(tpsEl);
const textEl = document.createElement("span");
textEl.className = "demo-output-text";
box.appendChild(textEl);
grid.appendChild(box);
// Look up TPS
let tps = null;
if (csvRows.length) {
const lookup = demoLookupTps(csvRows, out.model, selectedDevice, matchCriteria);
tps = lookup.found ? lookup.tps : (out.tps || null);
} else {
tps = out.tps || null;
}
if (tps != null) {
tpsEl.textContent = tps.toFixed(2) + " Tokens / sec";
tpsEl.classList.remove("oom");
textEl.style.display = "";
demoPreCalcHeight(box, textEl, out.text);
const handle = demoStreamText(textEl, out.text, tps);
activeStreams.push(handle);
} else {
tpsEl.textContent = "OOM";
tpsEl.classList.add("oom");
tpsEl.style.color = "";
textEl.style.display = "none";
box.style.minHeight = "";
}
});
}
function renderClip() {
const clip = clips[currentClipIdx];
// Title: clip label + setup details
h3.textContent = clip.label || data.title || "Output Examples";
clipSetup.textContent = clip.inference_setup || "";
clipSetup.style.display = clip.inference_setup ? "" : "none";
// Video — crossfade: keep old visible, load new behind, fade when frame ready
if (clip.video) {
videoWrap.style.display = "";
if (isFirstClip) {
// First clip: just load directly into videoA
videoA.src = clip.video;
videoA.style.opacity = "1";
videoA.load();
videoA.addEventListener("loadeddata", () => videoA.play(), { once: true });
isFirstClip = false;
} else {
// Crossfade: videoA is the old (visible), videoB gets the new source
videoB.src = clip.video;
videoB.style.opacity = "0";
videoB.load();
videoB.addEventListener("loadeddata", function onLoaded() {
videoB.removeEventListener("loadeddata", onLoaded);
videoB.play();
// Wait for actual frame render before fading
const startFade = () => {
videoB.style.opacity = "1";
videoA.style.opacity = "0";
// After transition, pause old and swap roles
setTimeout(() => {
videoA.pause();
videoA.removeAttribute("src");
videoA.load();
// Swap roles
const tmp = videoA;
videoA = videoB;
videoB = tmp;
}, 300);
};
if (videoB.requestVideoFrameCallback) {
videoB.requestVideoFrameCallback(startFade);
} else {
startFade();
}
});
}
} else {
videoWrap.style.display = "none";
}
// Prompt
if (clip.prompt) {
promptEl.innerHTML = "Prompt: " + clip.prompt.replace(/\n/g, "
");
promptEl.style.display = "";
} else {
promptEl.style.display = "none";
}
// Citation
if (clip.citation) {
if (clip.citation_url) {
citeEl.innerHTML = clip.citation.replace(
/Autonomous Vehicle Domain Adaptation Gallery/,
`Autonomous Vehicle Domain Adaptation Gallery`
);
} else {
citeEl.textContent = clip.citation;
}
citeEl.style.display = "";
} else {
citeEl.style.display = "none";
}
// Outputs
renderOutputs();
updateArrows();
}
// ── Toggle open/close ───────────────────────────────────────────────
toggle.addEventListener("click", () => {
const isOpen = content.classList.toggle("open");
toggle.classList.toggle("active", isOpen);
toggle.innerHTML = isOpen
? '▶ Hide Demo'
: '▶ Show Demo';
if (isOpen) {
renderClip();
} else {
cancelStreams();
}
});
inner.appendChild(card);
content.appendChild(inner);
section.appendChild(toggle);
section.appendChild(content);
container.appendChild(section);
}