function Sparkline({ points, color = "var(--ink)" }){ const w = 100, h = 22; if (!points || points.length === 0){ return ( ); } const step = w / (points.length - 1 || 1); const d = points.map((p, i) => `${i===0?"M":"L"}${i*step},${h - p*(h-2) - 1}`).join(" "); return ( ); } function HeroMetrics({ result }){ const cells = [ { lbl: "Compression Ratio", val: result ? `${result.ratio.toFixed(2)}×` : "—", delta: result ? `−${(100 - 100/result.ratio).toFixed(0)}% bytes` : "", deltaClass: "neg" }, { lbl: "Entropy", val: result ? result.entropy.toFixed(2) : "—", unit: "bits/sym" }, { lbl: "Encoding Efficiency", val: result ? `${(result.efficiency*100).toFixed(1)}` : "—", unit: "%" }, { lbl: "Total Latency", val: result ? `${(result.totalLatency*1000).toFixed(0)}` : "—", unit: "ms" }, ]; return (
{cells.map((c, i) => (
{c.lbl}
{c.val} {c.unit && {c.unit}}
{c.delta ?
{c.delta}
:
 
}
))}
); } function DetailTable({ result }){ const rows = [ { k: "Original size", v: result ? `${result.origBytes} B` : "—", lane: "var(--ink-3)" }, { k: "Compressed size", v: result ? `${result.compBytes} B` : "—", lane: "var(--accent)" }, { k: "Avg bits per symbol", v: result ? result.avgBits.toFixed(3) : "—" }, { k: "Shannon entropy", v: result ? result.entropy.toFixed(3) + " bits/sym" : "—" }, { k: "Efficiency (H/ℓ̄)", v: result ? (result.efficiency*100).toFixed(2) + " %" : "—" }, { k: "Stage 1 OCR latency", v: result ? fmtMs(result.ocrLatency) : "—" }, { k: "Stage 2 compress latency", v: result ? fmtMs(result.compLatency) : "—" }, { k: "Stage 2 decompress latency", v: result ? fmtMs(result.decLatency) : "—" }, { k: "Total end-to-end", v: result ? fmtMs(result.totalLatency): "—", emph: true }, ]; return ( {rows.map((r, i) => ( ))}
MetricValue
{r.lane && } {r.k} {r.v}
); } function BytesBar({ result }){ if (!result){ return
Run pipeline to compare byte lengths.
; } const maxB = Math.max(result.origBytes, result.compBytes); const origPct = (result.origBytes / maxB) * 100; const compPct = (result.compBytes / maxB) * 100; return (
Original
{result.origBytes} B
Compressed
{result.compBytes} B
); } Object.assign(window, { HeroMetrics, DetailTable, BytesBar, Sparkline });