// Slipstream - interactive presentation (buildless Preact + htm + Highcharts), backed by gr.Server. import { h, render } from "https://esm.sh/preact@10.25.4"; import { useState, useEffect, useRef, useMemo } from "https://esm.sh/preact@10.25.4/hooks"; import htm from "https://esm.sh/htm@3.1.1"; import { Client } from "https://esm.sh/@gradio/client@1.10.0"; const html = htm.bind(h); const HC = window.Highcharts; // ---- backend ------------------------------------------------------------------------------ let _client = null; async function api(name, payload = {}) { if (!_client) _client = await Client.connect(location.origin); return (await _client.predict("/" + name, payload)).data[0]; } // ---- palette / data encoding -------------------------------------------------------------- const FC = { classical: "#5aa9ff", ml: "#4ade80", foundation: "#fb923c", naive: "#8b93a7", control: "#c084fc", agent: "#f472b6", other: "#8b93a7" }; const ACCENT = "#7c8cff"; const STR = ["short", "medium", "long", "very_long"], STR_L = ["short", "medium", "long", "very long"]; const STAGES = ["0.25", "0.40", "0.60", "0.75"]; // metric at a chosen completion stage, or averaged across all of them ("avg") function metric(b, k, stage, field) { if (stage === "avg") { const vs = STAGES.map(s => b.methods[k]?.stages?.[s]?.[field]).filter(v => v != null); return vs.length ? vs.reduce((a, c) => a + c, 0) / vs.length : null; } return b.methods[k]?.stages?.[stage]?.[field]; } const stageLabel = (s) => s === "avg" ? "all snapshots (average)" : Math.round(parseFloat(s) * 100) + "% complete"; if (HC) HC.setOptions({ colors: [ACCENT], chart: { backgroundColor: "transparent", style: { fontFamily: "Inter, sans-serif" }, spacing: [8, 6, 8, 6] }, title: { style: { color: "#eef1f7", fontFamily: "Space Grotesk", fontSize: "15px", fontWeight: "600" } }, subtitle: { style: { color: "#8b93a7", fontSize: "12.5px" } }, xAxis: { labels: { style: { color: "#8b93a7", fontSize: "12px" } }, lineColor: "rgba(255,255,255,.12)", tickColor: "rgba(255,255,255,.12)", title: { style: { color: "#8b93a7" } } }, yAxis: { labels: { style: { color: "#8b93a7", fontSize: "12px" } }, gridLineColor: "rgba(255,255,255,.06)", title: { style: { color: "#8b93a7" } } }, legend: { itemStyle: { color: "#c7cdda", fontWeight: "500" }, itemHoverStyle: { color: "#fff" } }, tooltip: { backgroundColor: "rgba(14,17,24,.97)", borderColor: "rgba(255,255,255,.14)", borderRadius: 8, style: { color: "#eef1f7", fontSize: "12.5px" }, useHTML: true, outside: true }, plotOptions: { series: { animation: { duration: 900 } } }, credits: { enabled: false }, accessibility: { enabled: false }, }); const NAV = [ { id: "hero", n: "", t: "Slipstream" }, { id: "benchmark", n: "01", t: "The benchmark" }, { id: "gap", n: "02", t: "The gap" }, { id: "distill", n: "03", t: "To the edge" }, { id: "results", n: "04", t: "Results" }, { id: "modal", n: "05", t: "On Modal" }, { id: "demo", n: "06", t: "Try it live" }, { id: "releases", n: "07", t: "Releases" }, ]; // ---- chart component: draws in the first time it scrolls into view ------------------------- function Chart({ options, height = 380 }) { const ref = useRef(null), inst = useRef(null); useEffect(() => { if (!ref.current || !HC) return; const el = ref.current; const io = new IntersectionObserver((es) => { if (es[0].isIntersecting && options && !inst.current) inst.current = HC.chart(el, options); }, { threshold: 0.2 }); io.observe(el); return () => { io.disconnect(); if (inst.current) { try { inst.current.destroy(); } catch (e) {} inst.current = null; } }; }, [options]); return html`
`; } // ---- animated count-up -------------------------------------------------------------------- function CountUp({ to, suffix = "" }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; let done = false; const io = new IntersectionObserver((es) => { if (!es[0].isIntersecting || done) return; done = true; const dur = 1100, t0 = performance.now(); const tick = (t) => { const k = Math.min(1, (t - t0) / dur); const e = 1 - Math.pow(1 - k, 3); el.textContent = Math.round(to * e) + suffix; if (k < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }, { threshold: 0.5 }); io.observe(el); return () => io.disconnect(); }, [to]); return html`0${suffix}`; } // ---- option builders ---------------------------------------------------------------------- const stage40 = (b, k) => b.methods[k]?.stages?.["0.40"]; const strataFin = (b, k) => STR.map(s => b.methods[k]?.by_strata?.[s]?.finish_err_med ?? null); function leaderboardOpts(b, stage) { const keys = ["earned_schedule", "growth_curve", "xsm", "ml_tabpfn", "ml_catboost", "timesfm_2.5", "agent_deepseek_v4_flash", "student_Nemotron-4B_sft", "student_gemma-4-E2B_sft", "student_MiniCPM5-1B_sft"]; const label = { earned_schedule: "Earned Schedule", growth_curve: "Growth curve", xsm: "XSM", ml_tabpfn: "TabPFN (ML)", ml_catboost: "CatBoost (ML)", "timesfm_2.5": "TimesFM", agent_deepseek_v4_flash: "Agent (teacher)", "student_Nemotron-4B_sft": "Nemotron 4B ·distilled", "student_gemma-4-E2B_sft": "Gemma E2B ·distilled", "student_MiniCPM5-1B_sft": "MiniCPM5 1B ·distilled" }; const rows = keys.map(k => ({ k, m: b.methods[k], eac: metric(b, k, stage, "eac_ape_med") })) .filter(r => r.eac != null).sort((a, c) => c.eac - a.eac); return { chart: { type: "bar", height: 430 }, title: { text: "Cost-forecast error · " + stageLabel(stage) }, subtitle: { text: "median %, lower is better" }, xAxis: { categories: rows.map(r => label[r.k] || r.k), labels: { style: { fontSize: "12.5px", color: "#c7cdda" } } }, yAxis: { min: 0, title: { text: null } }, legend: { enabled: false }, tooltip: { pointFormat: "{point.y:.2f}% cost error" }, plotOptions: { bar: { borderRadius: 3, pointWidth: 16, dataLabels: { enabled: true, format: "{y:.1f}", style: { color: "#c7cdda", textOutline: "none", fontWeight: "600" } } } }, series: [{ data: rows.map(r => ({ y: r.eac, color: r.m.family === "agent" ? ACCENT : FC[r.m.family] })) }], }; } function blendOpts(b) { const ser = [ ["earned_schedule", "Earned Schedule", FC.classical, 2], ["ml_catboost", "ML reference-class", FC.ml, 2], ["agent_deepseek_v4_flash", "Agentic layer", ACCENT, 4], ].map(([k, name, color, lw]) => ({ name, color, lineWidth: lw, data: strataFin(b, k), marker: { radius: lw > 2 ? 5 : 4, symbol: "circle" } })); return { chart: { type: "line", height: 430 }, title: { text: "Finish-date error grows with project length - unless you blend" }, subtitle: { text: "median periods off the true finish, at 40% complete" }, xAxis: { categories: STR_L, title: { text: "project length" } }, yAxis: { min: 0, title: { text: "finish error (periods)" } }, tooltip: { shared: true, valueDecimals: 2, valueSuffix: " periods" }, series: ser, }; } function baseSftOpts(b, stage) { const studs = [["MiniCPM5-1B", "MiniCPM5 1B"], ["gemma-4-E2B", "Gemma E2B"], ["Nemotron-4B", "Nemotron 4B"], ["Qwen3.5-4B", "Qwen3.5 4B"], ["Qwen3.5-2B", "Qwen3.5 2B"]]; const vr = (k, v) => (metric(b, `student_${k}_${v}`, stage, "valid_rate") ?? 0) * 100; return { chart: { type: "column", height: 400 }, title: { text: "Off-the-shelf vs distilled: usable-forecast rate" }, subtitle: { text: "% of projects the small model returns a valid forecast for · " + stageLabel(stage) }, xAxis: { categories: studs.map(s => s[1]) }, yAxis: { min: 0, max: 100, title: { text: null }, labels: { format: "{value}%" } }, tooltip: { shared: true, valueDecimals: 1, valueSuffix: "%" }, plotOptions: { column: { borderRadius: 3, groupPadding: 0.12 } }, series: [ { name: "base (off the shelf)", color: "rgba(139,147,167,.5)", data: studs.map(s => vr(s[0], "base")) }, { name: "distilled", color: ACCENT, data: studs.map(s => vr(s[0], "sft")) }, ], }; } function scatterOpts(b, stage) { const CAPX = 12, CAPY = 5; const names = Object.keys(b.methods).filter(k => metric(b, k, stage, "eac_ape_med") != null); const byFam = {}; names.forEach(k => { const ex = metric(b, k, stage, "eac_ape_med"), fy = metric(b, k, stage, "finish_err_med"); if (ex == null || fy == null || ex > CAPX || fy > CAPY) return; const f = b.methods[k].family; (byFam[f] = byFam[f] || []).push({ x: ex, y: fy, name: k }); }); const FL = { classical: "classical", ml: "ML / tabular", foundation: "time-series FM", naive: "naive", control: "control", agent: "agentic" }; return { chart: { type: "scatter", height: 420, zoomType: "xy" }, title: { text: "Cost vs schedule · " + stageLabel(stage) + " - bottom-left is best" }, xAxis: { min: 0, max: CAPX, title: { text: "cost error %" }, gridLineWidth: 1 }, yAxis: { min: 0, max: CAPY, title: { text: "finish error (periods)" } }, tooltip: { pointFormat: "{point.name}
{point.x:.2f}% · {point.y:.2f} periods" }, plotOptions: { scatter: { marker: { radius: 5, symbol: "circle", states: { hover: { radiusPlus: 3 } } } } }, series: Object.keys(byFam).map(f => ({ name: FL[f] || f, color: f === "agent" ? ACCENT : FC[f], data: byFam[f], marker: { lineColor: "rgba(0,0,0,.4)", lineWidth: f === "agent" ? 1.2 : 0, radius: f === "agent" ? 7 : 5, symbol: f === "agent" ? "diamond" : "circle" } })), }; } function stratifiedOpts(b) { const keys = ["earned_schedule", "xsm", "growth_curve", "ml_tabpfn", "ml_catboost", "ml_lightgbm", "timesfm_2.5", "chronos_2", "agent_deepseek_v4_flash", "student_Nemotron-4B_sft"]; const label = { earned_schedule: "Earned Schedule", xsm: "XSM", growth_curve: "Growth curve", ml_tabpfn: "TabPFN", ml_catboost: "CatBoost", ml_lightgbm: "LightGBM", "timesfm_2.5": "TimesFM", chronos_2: "Chronos", agent_deepseek_v4_flash: "Agent (teacher)", "student_Nemotron-4B_sft": "Nemotron ·distilled" }; const rows = keys.filter(k => b.methods[k]); const CAP = 8, data = []; rows.forEach((k, yi) => STR.forEach((s, xi) => { const v = b.methods[k].by_strata?.[s]?.finish_err_med; if (v != null) data.push({ x: xi, y: yi, value: Math.min(v, CAP), actual: v }); })); return { chart: { type: "heatmap", height: 420 }, title: { text: "Finish error by project length" }, subtitle: { text: "periods off; pale = accurate, bright = inaccurate" }, xAxis: { categories: STR_L }, yAxis: { categories: rows.map(k => label[k] || k), reversed: true, title: { text: null }, labels: { style: { fontSize: "11.5px", color: "#c7cdda" } } }, colorAxis: { min: 0, max: CAP, stops: [[0, "#10331f"], [0.3, "#1f6b46"], [0.6, "#cfa53a"], [1, "#e0556b"]], labels: { style: { color: "#8b93a7" } } }, legend: { enabled: false }, tooltip: { formatter() { return `${rows.map(k => label[k] || k)[this.point.y]}
${STR_L[this.point.x]}: ${this.point.actual.toFixed(2)} periods`; } }, series: [{ borderWidth: 2, borderColor: "#08090d", data, dataLabels: { enabled: true, formatter() { return this.point.actual.toFixed(1); }, style: { fontSize: "10.5px", color: "#eef1f7", textOutline: "none" } } }], }; } // ---- live-demo formatting + charts -------------------------------------------------------- const money = (v) => v == null ? "-" : "£" + Math.round(v).toLocaleString(); const per = (v) => { if (v == null) return "-"; const r = Math.round(v * 10) / 10; return r + (r === 1 ? " period" : " periods"); }; // methods to draw on the live comparison, in fixed order (the agent is the headline) function demoRows(res, key) { const g = (o) => o ? o[key] : null; return [ { name: "Earned Schedule", v: g(res.classical?.earned_schedule), color: FC.classical }, { name: "TimesFM", v: g(res.timesfm), color: FC.foundation }, { name: "TabPFN", v: g(res.tabpfn), color: FC.ml }, { name: "Agentic layer", v: g(res.agent), color: ACCENT, bold: true }, ]; } function truthLine(value, text) { return [{ value, color: "#eef1f7", width: 2, dashStyle: "Dash", zIndex: 5, label: { text, style: { color: "#eef1f7", fontWeight: "600", fontSize: "11px" }, align: "right", x: -4 } }]; } function demoFinishOpts(res) { const rows = demoRows(res, "finish"); return { chart: { type: "bar", height: 250 }, title: { text: "Finish period" }, subtitle: { text: "when the project completes" }, xAxis: { categories: rows.map(r => r.name), labels: { style: { color: "#c7cdda", fontSize: "12px" } } }, yAxis: { min: 0, title: { text: null }, plotLines: truthLine(res.truth.finish, "actual " + res.truth.finish) }, legend: { enabled: false }, tooltip: { pointFormat: "{point.y:.1f} periods" }, plotOptions: { bar: { borderRadius: 3, pointWidth: 18, dataLabels: { enabled: true, format: "{y:.1f}", style: { color: "#c7cdda", textOutline: "none", fontWeight: "600" } } } }, series: [{ data: rows.map(r => r.v == null ? null : { y: r.v, color: r.color }) }], }; } function demoEacOpts(res) { const rows = demoRows(res, "eac"); return { chart: { type: "bar", height: 250 }, title: { text: "Final cost (EAC)" }, subtitle: { text: "total cost at completion" }, xAxis: { categories: rows.map(r => r.name), labels: { style: { color: "#c7cdda", fontSize: "12px" } } }, yAxis: { min: 0, title: { text: null }, labels: { formatter() { return "£" + Math.round(this.value / 1000) + "k"; } }, plotLines: truthLine(res.truth.eac, "actual " + money(res.truth.eac)) }, legend: { enabled: false }, tooltip: { pointFormatter() { return "" + money(this.y) + ""; } }, plotOptions: { bar: { borderRadius: 3, pointWidth: 18, dataLabels: { enabled: true, formatter() { return "£" + Math.round(this.y / 1000) + "k"; }, style: { color: "#c7cdda", textOutline: "none", fontWeight: "600" } } } }, series: [{ data: rows.map(r => r.v == null ? null : { y: r.v, color: r.color }) }], }; } // ---- slides ------------------------------------------------------------------------------- const Slide = (id, ...kids) => html`
${kids}
`; function Hero({ bench, stage }) { const opts = useMemo(() => bench ? leaderboardOpts(bench, stage) : null, [bench, stage]); return html`

Slipstream

project-controls forecasting

Forecasting a project's final cost and finish date - before it finishes.

A benchmark of 37 methods on real projects, an agentic layer that blends the best of them, and small models that run it on the edge.

${opts && html`<${Chart} options=${opts} height=${430} />`}
scroll ↓
`; } function Benchmark({ summary }) { const s = summary || {}; const cells = [ [s.n_projects ?? 0, "", "real projects scored", "held-out" + (s.n_sourced ? `, of ${s.n_sourced} with outcomes` : "")], [s.n_methods ?? 0, "", "methods compared", "classical · ML · time-series FMs · agents"], [s.stages ? s.stages.length : 0, "", "snapshots", "forecast at 25 / 40 / 60 / 75% done"], [s.families ? s.families.length : 0, "", "method families", "from simple formulas to AI agents"], ]; return Slide("benchmark", html`01 - The benchmark`, html`

Forecast a project before it finishes

`, html`

Reveal only the first part of a project's history, then predict its total final cost and the period it will finish. Every method is scored the same way, on the same real projects it never saw in training.

`, html`
${cells.map(([n, sfx, lab, sub]) => html`
<${CountUp} to=${n} suffix=${sfx} />
${lab}
${sub}
`)}
`); } function Gap({ bench }) { const opts = useMemo(() => bench ? blendOpts(bench) : null, [bench]); return Slide("gap", html`02 - The gap an agent fills`, html`

No single method wins across a project's life

`, html`
${opts && html`<${Chart} options=${opts} height=${430} />`}
`, html`

Earned Schedule (the industry standard) is excellent early but its finish forecast collapses on long projects - from 0.35 to 5.4 periods. ML reference-class models stay robust late but are weaker early. The agentic layer writes code to call every tool, trusts the ML reference-class for long-horizon timing and Earned Schedule's BAC/CPI for cost, and explains its choice - the only method strong across all horizons.

`); } function Distill({ bench, stage }) { const opts = useMemo(() => bench ? baseSftOpts(bench, stage) : null, [bench, stage]); return Slide("distill", html`03 - Distilling to the edge`, html`

Shrink the agent for air-gapped, on-device forecasting

`, html`

Much project data - defence, infrastructure, government - can't leave its environment. So we distil the teacher's reasoning into 1-4B open models that run offline.

`, html`
${opts && html`<${Chart} options=${opts} height=${400} />`}
`, html`

Off the shelf, a 1B model returns a usable forecast under 2% of the time. After distillation the best reach parity with the teacher and Earned Schedule (~2.3-2.4% cost error) - small enough to forecast at the edge.

`); } function Results({ bench, stage }) { const sc = useMemo(() => bench ? scatterOpts(bench, stage) : null, [bench, stage]); const st = useMemo(() => bench ? stratifiedOpts(bench) : null, [bench]); // by-strata only at 40% return Slide("results", html`04 - Results & limits`, html`

What the benchmark shows, honestly

`, html`
${sc && html`<${Chart} options=${sc} height=${420} />`}
${st && html`<${Chart} options=${st} height=${420} />`}
`, html``); } function Modal_() { const steps = [ ["Simulate", "Real libraries have structure but not full cost/progress outcomes - we simulate them to completion."], ["Generate", "The teacher agent runs the code-action loop over the simulated projects; its reasoning traces are captured."], ["Fine-tune", "Five small models LoRA-fine-tuned on the traces, each on the stack it needs."], ["Evaluate", "Every model + baseline scored through one shared harness on the held-out real projects."], ]; return Slide("modal", html`05 - Built on Modal`, html`

The whole pipeline runs on Modal

`, html`

Simulation, trace generation, fine-tuning and evaluation - all on Modal's GPUs, with a strict firewall: distillation seeds are simulation-only, the real projects stay a clean test set.

`, html`
${steps.map(([t, d], i) => html`
${i + 1}
${t}
${d}
`)}
`); } function Releases() { const HF = "https://huggingface.co/"; const items = [ ["Distillation dataset", "Multi-turn code-action forecasting traces - the data the students learn from (CC-BY-4.0).", "datasets/build-small-hackathon/slipstream-evm-sft", "slipstream-evm-sft"], ["MiniCPM5-1B agent", "From an unusable 1B base to Earned-Schedule parity.", "build-small-hackathon/slipstream-minicpm5-1b-evm", "slipstream-minicpm5-1b-evm"], ["Nemotron-3-Nano 4B agent", "The Mamba-hybrid agent, distilled.", "build-small-hackathon/slipstream-nemotron3-nano-4b-evm", "slipstream-nemotron3-nano-4b-evm"], ["Gemma-E2B agent", "The compact Gemma agent.", "build-small-hackathon/slipstream-gemma4-e2b-evm", "slipstream-gemma4-e2b-evm"], ]; return Slide("releases", html`07 - Open releases`, html`

Released on Hugging Face

`, html`

On the Build Small Hackathon organisation, with a full write-up. The dataset is CC-BY-4.0; each model inherits its base model's licence. Trained, evaluated and benchmarked entirely on Modal.

`, html`
${items.map(([t, d, path, slug]) => html` ${t}
${d}
build-small-hackathon/${slug}
`)}
`, html`Read the technical write-up →`); } function Demo() { const [meta, setMeta] = useState(null); const [pid, setPid] = useState(""); const [stage, setStage] = useState(0.4); const [model, setModel] = useState("MiniCPM5-1B"); const [res, setRes] = useState(null); const [status, setStatus] = useState("idle"); // idle | running | done | error const [msg, setMsg] = useState(""); const poll = useRef(null); useEffect(() => { fetch("/demo/projects").then(r => r.json()).then(m => { if (m.error) { setMsg(m.error); return; } setMeta(m); setModel(m.default_model || "MiniCPM5-1B"); const pick = m.projects.find(p => p.strata === "long") || m.projects[0]; if (pick) setPid(pick.id); }).catch(e => setMsg(String(e))); return () => clearInterval(poll.current); }, []); const run = async () => { if (!pid) return; clearInterval(poll.current); setRes(null); setStatus("running"); setMsg("Every run cold-starts a fresh GPU on Modal, so expect roughly 5-7 minutes. Results stream in as each method lands - Earned Schedule and the real outcome are instant; TabPFN and the live agent follow."); let base; try { const r = await fetch("/demo/forecast", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ project_id: pid, stage, model }) }); base = await r.json(); } catch (e) { setStatus("error"); setMsg("Request failed: " + e); return; } if (base.error) { setStatus("error"); setMsg(base.error); return; } setRes(base); const j = base.jobs || {}; const t0 = Date.now(); poll.current = setInterval(async () => { let pr; try { pr = await (await fetch(`/demo/result?agent=${j.agent || ""}&tabpfn=${j.tabpfn || ""}`)).json(); } catch (e) { return; } setRes(prev => { if (!prev) return prev; const n = { ...prev }; let ch = false; if (pr.timesfm && !prev.timesfm) { n.timesfm = pr.timesfm; ch = true; } if (pr.tabpfn && !prev.tabpfn) { n.tabpfn = pr.tabpfn; ch = true; } if (pr.agent && !prev.agent) { n.agent = pr.agent; ch = true; } if (pr.agent_error && !prev.agent_error) { n.agent_error = pr.agent_error; ch = true; } return ch ? n : prev; }); const secs = Math.round((Date.now() - t0) / 1000), mm = Math.floor(secs / 60), ss = secs % 60; const tick = (ok) => ok ? "✓" : "…"; setMsg(`Running live on Modal · ${mm}:${String(ss).padStart(2, "0")} - ` + `TabPFN ${tick(pr.tabpfn)} · agentic layer ${tick(pr.agent)} (cold start, ~5-7 min)`); if (pr.done) { clearInterval(poll.current); setStatus("done"); setMsg(""); } }, 4000); }; const finishOpts = useMemo(() => res ? demoFinishOpts(res) : null, [res]); const eacOpts = useMemo(() => res ? demoEacOpts(res) : null, [res]); const grouped = useMemo(() => { const g = {}; (meta?.projects || []).forEach(p => (g[p.strata] = g[p.strata] || []).push(p)); return g; }, [meta]); // headline readout once the agent has landed let readout = null; if (res && res.agent && res.agent.finish != null) { const a = res.agent, T = res.truth; const fErr = Math.abs(a.finish - T.finish), cErr = Math.abs(a.eac - T.eac) / T.eac * 100; const es = res.classical?.earned_schedule; const esF = es && es.finish != null ? Math.abs(es.finish - T.finish) : null; readout = html`
The distilled ${res.model} agent forecast a finish within ${per(fErr)}${" "} and a final cost within ${cErr.toFixed(1)}% of the real outcome${ esF != null && esF > fErr + 0.5 ? html` - versus Earned Schedule's ${per(esF)} off on the finish` : ""}.
`; } const STG = [[0.25, "25%"], [0.4, "40%"], [0.6, "60%"], [0.75, "75%"]]; return Slide("demo", html`06 - Try it live`, html`

Forecast a real project, live

`, html`

Pick a real held-out project and reveal only part of its history. The agentic layer runs live on Modal - calling every tool and reconciling them - next to Earned Schedule, TimesFM and TabPFN, against the true outcome. Each run cold-starts a GPU, so it takes ~5-7 minutes and the methods stream in as they finish.

`, html`
${STG.map(([v, l]) => html``)}
`, msg ? html`
${msg}
` : null, res ? html`
${finishOpts && html`<${Chart} options=${finishOpts} height=${250} />`}
${eacOpts && html`<${Chart} options=${eacOpts} height=${250} />`}
` : null, readout, res && res.agent && res.agent.trace && res.agent.trace.length ? html`
How the agent reasoned (${res.agent.turns} turns · ${res.agent.exit_reason}) ${res.agent.trace.map(t => html`
${t.reasoning ? html`
${t.reasoning}
` : null} ${t.code ? html`
${t.code}
` : null} ${t.output ? html`
${t.output}
` : null}
`)}
` : null); } // ---- app shell ---------------------------------------------------------------------------- function App() { const [d, setD] = useState({ summary: null, bench: null }); const [stage, setStage] = useState("0.40"); const [err, setErr] = useState(null); const deckRef = useRef(null); const nav = (dir) => { const deck = deckRef.current; if (!deck) return; const ss = [...deck.querySelectorAll(".slide")]; const cur = ss.findIndex(s => s.getBoundingClientRect().top >= -window.innerHeight * 0.4); const i = Math.max(0, Math.min(ss.length - 1, (cur < 0 ? 0 : cur) + dir)); ss[i]?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { api("summary").then(s => setD(p => ({ ...p, summary: s }))).catch(e => setErr(String(e))); api("benchmark").then(b => setD(p => ({ ...p, bench: b }))).catch(e => setErr(String(e))); }, []); // scroll behaviour set up once the slides exist (both summary+bench loaded -> render gate passed). useEffect(() => { if (!d.bench || !d.summary) return; const slides = [...document.querySelectorAll(".slide")]; const prog = document.querySelector(".progress"); const STAGE_SLIDES = ["hero", "distill", "results"]; // slides whose charts are stage-dependent const ratios = new Map(); const io = new IntersectionObserver((es) => { es.forEach(e => { ratios.set(e.target, e.intersectionRatio); if (e.isIntersecting) e.target.classList.add("in"); }); let best = null, bestR = -1; // global max over ALL slides, not just changed entries (avoids label lag) slides.forEach(s => { const r = ratios.get(s) || 0; if (r > bestR) { bestR = r; best = s; } }); if (best && bestR > 0) { const id = best.dataset.id, i = NAV.findIndex(n => n.id === id); if (prog) prog.style.width = ((i + 1) / NAV.length * 100) + "%"; const lab = document.querySelector(".ctl-pos"); if (lab) lab.textContent = String(i + 1).padStart(2, "0") + " / 0" + NAV.length + " · " + NAV[i].t; const sel = document.querySelector(".stagesel"), show = STAGE_SLIDES.includes(id); if (sel) { sel.style.opacity = show ? "1" : "0"; sel.style.pointerEvents = show ? "auto" : "none"; } } }, { threshold: [0, 0.2, 0.4, 0.6, 0.8, 1] }); slides.forEach(s => io.observe(s)); const onKey = (ev) => { if (["ArrowDown", "PageDown", "ArrowRight", " "].includes(ev.key)) { ev.preventDefault(); nav(1); } else if (["ArrowUp", "PageUp", "ArrowLeft"].includes(ev.key)) { ev.preventDefault(); nav(-1); } }; window.addEventListener("keydown", onKey); return () => { io.disconnect(); window.removeEventListener("keydown", onKey); }; }, [d.bench, d.summary]); if (err) return html`
Backend error: ${err}
`; if (!d.bench || !d.summary) return html`
Loading the benchmark…
`; const STAGE_OPTS = [["0.25", "25%"], ["0.40", "40%"], ["0.60", "60%"], ["0.75", "75%"], ["avg", "Avg"]]; return html`
nav(-99)}>Slipstream
charts at ${STAGE_OPTS.map(([v, l]) => html``)}
<${Hero} bench=${d.bench} stage=${stage} /> <${Benchmark} summary=${d.summary} /> <${Gap} bench=${d.bench} /> <${Distill} bench=${d.bench} stage=${stage} /> <${Results} bench=${d.bench} stage=${stage} /> <${Modal_} /> <${Demo} /> <${Releases} />
01 / 0${NAV.length} · Slipstream
`; } render(html`<${App} />`, document.getElementById("app"));