"use client"; import { motion } from "framer-motion"; import { COLORS, VizFrame } from "./common"; type Stage = { label: string; shape: string; kind: "input" | "conv" | "pool" | "fc" | "out"; // Visual hints — height of the box, "depth" rectangles count size: number; channels: number; }; const STAGES: Stage[] = [ { label: "input", shape: "32×32×1", kind: "input", size: 96, channels: 1 }, { label: "C1 · 5×5 conv", shape: "28×28×6", kind: "conv", size: 86, channels: 6 }, { label: "S2 · 2×2 pool", shape: "14×14×6", kind: "pool", size: 60, channels: 6 }, { label: "C3 · 5×5 conv", shape: "10×10×16", kind: "conv", size: 50, channels: 12 }, { label: "S4 · 2×2 pool", shape: "5×5×16", kind: "pool", size: 30, channels: 12 }, { label: "C5 · fc-conv", shape: "1×1×120", kind: "conv", size: 18, channels: 18 }, { label: "F6 · dense", shape: "84", kind: "fc", size: 12, channels: 16 }, { label: "output · softmax", shape: "10 classes", kind: "out", size: 10, channels: 10 }, ]; const COLOR_OF: Record = { input: COLORS.ink, conv: COLORS.accent, pool: COLORS.green, fc: COLORS.honey, out: COLORS.red, }; export function LeNetArchitecture({ width = 1040, height = 380, }: { width?: number; height?: number; }) { const padX = 30; const stepW = (width - padX * 2) / STAGES.length; const cy = height / 2; return ( {STAGES.map((s, i) => { const cx = padX + i * stepW + stepW / 2; const sliceW = Math.max(6, s.size * 0.4); return ( {/* Stack of "feature maps": draw `channels` overlapping rectangles */} {Array.from({ length: Math.min(6, Math.ceil(s.channels / 3)) }, (_, k) => ( ))} {/* Top label */} {s.label} {/* Bottom shape */} {s.shape} {/* Connecting arrow */} {i < STAGES.length - 1 ? ( ) : null} ); })} spatial size shrinks · channels grow · ≈ 60 K parameters ); }