carbon-demo / assets /js /shared /helpers.js
lvwerra's picture
lvwerra HF Staff
Intro tab + central-dogma primer + em-dash sweep
5ea40ce
// =========================================================================
// Shared helpers
// =========================================================================
const DARK_RGB = [31, 31, 29];
const MID_RGB = [136, 136, 136];
const RED_RGB = [188, 46, 37];
const PROMPT_RGB = [170, 170, 170];
function lerp(a, b, t) { return Math.round(a + (b - a) * t); }
function lerpRgb(c1, c2, t) {
return [lerp(c1[0], c2[0], t), lerp(c1[1], c2[1], t), lerp(c1[2], c2[2], t)];
}
function logprobRgb(lp, range) {
if (lp == null || isNaN(lp) || !range) return DARK_RGB;
const { min, mid, max } = range;
if (max === min) return MID_RGB;
if (lp >= mid) {
const denom = max - mid;
const t = denom > 0 ? Math.min(1, Math.max(0, (max - lp) / denom)) : 0;
return lerpRgb(DARK_RGB, MID_RGB, t);
}
const denom = mid - min;
const t = denom > 0 ? Math.min(1, Math.max(0, (mid - lp) / denom)) : 0;
return lerpRgb(MID_RGB, RED_RGB, t);
}
function lpRangeOf(tokens) {
let min = Infinity, max = -Infinity, sum = 0, n = 0;
for (const t of tokens) {
const lp = t.logprob;
if (lp == null || isNaN(lp)) continue;
if (lp < min) min = lp;
if (lp > max) max = lp;
sum += lp; n++;
}
return n ? { min, mid: sum / n, max } : null;
}
function meanLogprob(tokens) {
const r = lpRangeOf(tokens);
return r ? r.mid : null;
}
// Render a sequence line-by-line with optional per-base coloring fn `colorAt(absIdx, base)`.
// 10-bp blocks separated by 2 spaces, position number prefix.
function renderSeq(el, seq, basesPerLine, colorAt) {
if (!seq) {
el.classList.add("empty");
el.textContent = "·";
return;
}
el.classList.remove("empty");
const parts = [];
for (let i = 0; i < seq.length; i += basesPerLine) {
const lineSeq = seq.slice(i, i + basesPerLine);
const pos = String(i + 1).padStart(5, " ");
let html = `<span class="pos">${pos}</span> `;
let j = 0;
while (j < lineSeq.length) {
if (j > 0 && j % 10 === 0) html += " ";
const absIdx = i + j;
const c = colorAt(absIdx, lineSeq[j]);
// Group identical-style runs within the 10-base block.
const blockEnd = Math.min(lineSeq.length, Math.floor(j / 10) * 10 + 10);
let runEnd = j + 1;
while (runEnd < blockEnd) {
const cn = colorAt(i + runEnd, lineSeq[runEnd]);
if (cn.style !== c.style) break;
runEnd++;
}
html += `<span style="${c.style}">${lineSeq.slice(j, runEnd)}</span>`;
j = runEnd;
}
parts.push(`<div>${html}</div>`);
}
el.innerHTML = parts.join("");
}