// Stage 04 — feed-forward MLP. // Visualized as: vector expands up to 4×, passes through nonlinearity, projects back down. function StageMLP({ tokens, activeIdx, progress, active, nLayers = 32, onExplain }) { const activeId = tokens[activeIdx]?.id ?? 0; const p = active ? progress : 0; // three columns of bars: input (d), expanded (4d), output (d) const nIn = 24, nHidden = 48, nOut = 24; const inputVals = React.useMemo(() => { const r = seededRand(activeId * 41 + 11); return Array.from({ length: nIn }, () => (r() - 0.5) * 2); }, [activeId]); const hiddenVals = React.useMemo(() => { const r = seededRand(activeId * 41 + 29); return Array.from({ length: nHidden }, () => Math.max(0, (r() - 0.3) * 2.4)); // GELU-ish, non-negative-ish }, [activeId]); const outputVals = React.useMemo(() => { const r = seededRand(activeId * 41 + 53); return Array.from({ length: nOut }, () => (r() - 0.5) * 2); }, [activeId]); // phases const phaseUp = clamp(p / 0.4, 0, 1); const phaseAct = clamp((p - 0.4) / 0.2, 0, 1); const phaseDown = clamp((p - 0.6) / 0.4, 0, 1); const barH = 80; const Col = ({ vals, max = 1, reveal, color = 'var(--ink)', absolute = false }) => (