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 (
| Metric | Value |
{rows.map((r, i) => (
|
{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 });