import { useEffect, useRef } from "react"; import { fmtParams, latticeAxisOf } from "../spec.js"; // One column tried to hold the model summary, the sweep directions, the run // metrics and every layer at once, so everything was cramped and the layer // list — the part that changes as you watch — sat below the fold. Tabs put one // concern on screen at a time; the run metrics moved out entirely, to the dock // under the scene where a training curve has room to be a curve. const S = { panel: { width: 320, height: "100%", display: "flex", flexDirection: "column", background: "linear-gradient(180deg, #131926 0%, #10141d 42%, #0e121a 100%)", borderRight: "1px solid #1e2635", flexShrink: 0, }, head: { padding: "16px 18px 0" }, body: { flex: 1, overflowY: "auto", padding: "4px 18px 18px" }, h1: { fontSize: 15, fontWeight: 650, letterSpacing: 0.2, marginBottom: 2 }, sub: { color: "#8b95a8", fontSize: 12, marginBottom: 12 }, tabs: { display: "flex", gap: 2, padding: "0 12px", borderBottom: "1px solid #1e2635", }, tab: (active) => ({ flex: 1, background: "none", border: "none", borderBottom: active ? "2px solid #ffc061" : "2px solid transparent", color: active ? "#e8eef8" : "#7d8aa3", fontSize: 12.5, fontWeight: active ? 650 : 500, padding: "9px 4px", cursor: "pointer", letterSpacing: 0.3, }), section: { color: "#5d6b84", fontSize: 10.5, fontWeight: 700, letterSpacing: 1.4, textTransform: "uppercase", margin: "16px 2px 6px", }, card: { background: "#151b28", border: "1px solid #232d40", borderRadius: 8, padding: "10px 12px", }, row: { display: "flex", justifyContent: "space-between", padding: "2px 0", fontSize: 13, }, key: { color: "#8b95a8" }, warn: { background: "#2a1418", border: "1px solid #7f1d1d", color: "#fca5a5", borderRadius: 8, padding: "8px 12px", marginTop: 10, fontSize: 13, }, layer: (active) => ({ position: "relative", overflow: "hidden", display: "flex", alignItems: "center", gap: 8, padding: "6px 10px", borderRadius: 6, cursor: "pointer", fontSize: 13, background: active ? "#22304c" : "transparent", border: active ? "1px solid #41568a" : "1px solid transparent", boxShadow: active ? "inset 3px 0 0 #ffc061" : "none", }), // The sweep's progress *through the active layer*, drawn behind its row. layerFill: { position: "absolute", inset: 0, transformOrigin: "left center", background: "linear-gradient(90deg, rgba(255,192,97,0.20), rgba(255,192,97,0.05))", pointerEvents: "none", }, chip: { fontSize: 11, padding: "1px 7px", borderRadius: 99, background: "#233049", color: "#9fb3d9", }, controls: { display: "flex", gap: 8, marginTop: 10 }, btn: { background: "#1c2536", color: "#d6dbe4", border: "1px solid #2b3850", borderRadius: 6, padding: "7px 12px", cursor: "pointer", fontSize: 13, flex: 1, }, select: { background: "#1c2536", color: "#d6dbe4", border: "1px solid #2b3850", borderRadius: 6, padding: "6px 8px", fontSize: 13, width: "100%", }, switch: (on) => ({ display: "flex", alignItems: "center", gap: 10, width: "100%", background: on ? "#1d2b21" : "#1c2536", color: on ? "#9ece6a" : "#d6dbe4", border: `1px solid ${on ? "#2f6e42" : "#2b3850"}`, borderRadius: 8, padding: "10px 12px", cursor: "pointer", fontSize: 13.5, fontWeight: 600, textAlign: "left", }), knob: (on) => ({ width: 30, height: 17, borderRadius: 99, background: on ? "#2f6e42" : "#2b3850", position: "relative", flexShrink: 0, transition: "background 160ms ease", }), dot: (on) => ({ position: "absolute", top: 2, left: on ? 15 : 2, width: 13, height: 13, borderRadius: 99, background: on ? "#9ece6a" : "#7d8aa3", transition: "left 160ms ease", }), note: { color: "#5d6b84", fontSize: 11.5, marginTop: 8, lineHeight: 1.5 }, }; // Progress through the active layer, written straight to the DOM node. Going // through React state here would re-render the whole panel sixty times a // second to move one bar. function LayerFill({ anim }) { const ref = useRef(); useEffect(() => { let raf; const tick = () => { const el = ref.current; if (el) el.style.transform = `scaleX(${anim.current.progress})`; raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [anim]); return
; } function ModelTab({ parsed }) { const { spec } = parsed; const m = spec.model; const cells = spec.lattice.cells; return ( <>