// 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 }) => (
{vals.map((v, i) => { const shown = reveal * vals.length > i; const h = absolute ? Math.min(1, v / max) : Math.min(1, Math.abs(v) / max); const sign = absolute ? 1 : Math.sign(v); return (
); })}
); return (
input · d
0 ? 'var(--ink)' : 'var(--text-faint)', paddingBottom: 28, textShadow: phaseUp > 0 ? '0 0 8px var(--ink)' : 'none', transition: 'color 200ms' }}>W↑
hidden · 4d (GELU) 0 ? 'var(--amber)' : 'var(--text-faint)', textShadow: phaseAct > 0 ? '0 0 6px var(--amber)' : 'none' }}>nonlinearity
0.2 ? 'var(--amber)' : 'var(--ink)'} absolute />
0 ? 'var(--ink)' : 'var(--text-faint)', paddingBottom: 28, textShadow: phaseDown > 0 ? '0 0 8px var(--ink)' : 'none', transition: 'color 200ms' }}>W↓
output · d (+ residual)
{/* layer stack indicator */}
layer
{Array.from({ length: nLayers }).map((_, i) => { const reached = active && (progress * nLayers) > i; return (
); })}
{String(Math.min(nLayers, Math.ceil((active ? progress : 0) * nLayers))).padStart(2, '0')} / {nLayers}
); } window.StageMLP = StageMLP;