{"project":{"id":"qesHYUH","userId":"davidyarham@gmail.com","username":null,"userPicture":null,"name":"Neural Network Playground","thumbnail":"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","visible":true,"contributors":"","githubRepo":null,"forkedFrom":null,"tags":"","files":{"folder":"","files":[{"name":"index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Untitled</title>\n  <link rel=\"stylesheet\" href=\"style.css\">\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Neural Network Playground</title>\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js\"></script>\n<script src=\"https://unpkg.com/lucide@latest/dist/umd/lucide.js\"></script>\n<link href=\"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=Inter:wght@400;500;600&display=swap\" rel=\"stylesheet\">\n\n</head>\n<body>\n<div class=\"app\">\n  <!-- Header -->\n  <header class=\"header\">\n    <div class=\"header__logo\">\n      <i data-lucide=\"brain-circuit\"></i>\n      <span>Neural Network Playground</span>\n    </div>\n    <div class=\"header__badge\">XOR Classifier</div>\n  </header>\n\n  <!-- Main Layout -->\n  <main class=\"main\">\n\n    <!-- LEFT: Network Visualizer -->\n    <section class=\"panel panel--network\" aria-label=\"Network Visualizer\">\n      <div class=\"panel__header\">\n        <i data-lucide=\"cpu\"></i>\n        <h2>Network Architecture</h2>\n        <span class=\"panel__sub\">2 → 4 → 1</span>\n      </div>\n      <canvas id=\"network-canvas\" width=\"480\" height=\"340\" aria-label=\"Neural network diagram\"></canvas>\n      <div class=\"activations-row\">\n        <div class=\"activation-pill\" id=\"act-00\">\n          <span class=\"act-label\">x₁=0, x₂=0</span>\n          <span class=\"act-output\" id=\"out-00\">—</span>\n        </div>\n        <div class=\"activation-pill\" id=\"act-01\">\n          <span class=\"act-label\">x₁=0, x₂=1</span>\n          <span class=\"act-output\" id=\"out-01\">—</span>\n        </div>\n        <div class=\"activation-pill\" id=\"act-10\">\n          <span class=\"act-label\">x₁=1, x₂=0</span>\n          <span class=\"act-output\" id=\"out-10\">—</span>\n        </div>\n        <div class=\"activation-pill\" id=\"act-11\">\n          <span class=\"act-label\">x₁=1, x₂=1</span>\n          <span class=\"act-output\" id=\"out-11\">—</span>\n        </div>\n      </div>\n    </section>\n\n    <!-- CENTER: Controls + Decision Boundary -->\n    <section class=\"panel panel--controls\" aria-label=\"Controls\">\n      <div class=\"panel__header\">\n        <i data-lucide=\"sliders-horizontal\"></i>\n        <h2>Training Controls</h2>\n      </div>\n\n      <div class=\"controls-grid\">\n        <div class=\"control-group\">\n          <label for=\"lr-slider\">Learning Rate <span class=\"mono\" id=\"lr-val\">0.1</span></label>\n          <input type=\"range\" id=\"lr-slider\" min=\"0.001\" max=\"1\" step=\"0.001\" value=\"0.1\" aria-label=\"Learning rate\">\n        </div>\n        <div class=\"control-group\">\n          <label for=\"hidden-slider\">Hidden Neurons <span class=\"mono\" id=\"hidden-val\">4</span></label>\n          <input type=\"range\" id=\"hidden-slider\" min=\"2\" max=\"8\" step=\"1\" value=\"4\" aria-label=\"Hidden neurons\">\n        </div>\n        <div class=\"control-group\">\n          <label for=\"activation-select\">Activation</label>\n          <select id=\"activation-select\" aria-label=\"Activation function\">\n            <option value=\"sigmoid\">Sigmoid</option>\n            <option value=\"tanh\">Tanh</option>\n            <option value=\"relu\">ReLU</option>\n          </select>\n        </div>\n      </div>\n\n      <div class=\"btn-row\">\n        <button class=\"btn btn--primary\" id=\"btn-train\" aria-label=\"Start training\">\n          <i data-lucide=\"play\"></i> Train\n        </button>\n        <button class=\"btn btn--ghost\" id=\"btn-step\" aria-label=\"Step one epoch\">\n          <i data-lucide=\"skip-forward\"></i> Step\n        </button>\n        <button class=\"btn btn--danger\" id=\"btn-reset\" aria-label=\"Reset network\">\n          <i data-lucide=\"rotate-ccw\"></i> Reset\n        </button>\n      </div>\n\n      <div class=\"stats-bar\">\n        <div class=\"stat\">\n          <span class=\"stat__label\">Epoch</span>\n          <span class=\"stat__value mono\" id=\"stat-epoch\">0</span>\n        </div>\n        <div class=\"stat\">\n          <span class=\"stat__label\">Loss</span>\n          <span class=\"stat__value mono\" id=\"stat-loss\">—</span>\n        </div>\n        <div class=\"stat\">\n          <span class=\"stat__label\">Accuracy</span>\n          <span class=\"stat__value mono\" id=\"stat-acc\">—</span>\n        </div>\n      </div>\n\n      <!-- Decision Boundary Canvas -->\n      <div class=\"panel__header\" style=\"margin-top:1rem\">\n        <i data-lucide=\"grid-3x3\"></i>\n        <h2>Decision Boundary</h2>\n      </div>\n      <canvas id=\"boundary-canvas\" width=\"260\" height=\"260\" aria-label=\"Decision boundary heatmap\"></canvas>\n      <!-- XOR Points Legend -->\n      <div class=\"legend-row\">\n        <span class=\"legend-dot legend-dot--zero\"></span><span>XOR = 0</span>\n        <span class=\"legend-dot legend-dot--one\"></span><span>XOR = 1</span>\n      </div>\n    </section>\n\n    <!-- RIGHT: Loss Chart -->\n    <section class=\"panel panel--chart\" aria-label=\"Loss Chart\">\n      <div class=\"panel__header\">\n        <i data-lucide=\"trending-down\"></i>\n        <h2>Training Loss</h2>\n      </div>\n      <div class=\"chart-wrap\">\n        <canvas id=\"loss-chart\" aria-label=\"Loss over epochs chart\"></canvas>\n      </div>\n\n      <div class=\"panel__header\" style=\"margin-top:1.25rem\">\n        <i data-lucide=\"table-2\"></i>\n        <h2>Truth Table</h2>\n      </div>\n      <table class=\"truth-table\" aria-label=\"XOR truth table with predictions\">\n        <thead>\n          <tr><th>x₁</th><th>x₂</th><th>Target</th><th>Predicted</th><th></th></tr>\n        </thead>\n        <tbody id=\"truth-table-body\">\n          <tr><td>0</td><td>0</td><td>0</td><td class=\"pred\" id=\"pred-00\">—</td><td class=\"verdict\" id=\"verd-00\"></td></tr>\n          <tr><td>0</td><td>1</td><td>1</td><td class=\"pred\" id=\"pred-01\">—</td><td class=\"verdict\" id=\"verd-01\"></td></tr>\n          <tr><td>1</td><td>0</td><td>1</td><td class=\"pred\" id=\"pred-10\">—</td><td class=\"verdict\" id=\"verd-10\"></td></tr>\n          <tr><td>1</td><td>1</td><td>0</td><td class=\"pred\" id=\"pred-11\">—</td><td class=\"verdict\" id=\"verd-11\"></td></tr>\n        </tbody>\n      </table>\n\n      <div class=\"speed-control\">\n        <label for=\"speed-slider\"><i data-lucide=\"zap\"></i> Speed</label>\n        <input type=\"range\" id=\"speed-slider\" min=\"1\" max=\"50\" step=\"1\" value=\"5\" aria-label=\"Training speed\">\n        <span class=\"mono\" id=\"speed-val\">5×</span>\n      </div>\n    </section>\n  </main>\n</div>\n\n  <script type=\"module\" src=\"main.js\"></script>\n</body>\n</html>"},{"name":"main.js","content":"// ── XOR Dataset ──\nconst XOR_DATA = [\n  { input: [0, 0], target: 0 },\n  { input: [0, 1], target: 1 },\n  { input: [1, 0], target: 1 },\n  { input: [1, 1], target: 0 },\n];\n\n// ── Activation Functions ──\nconst activations = {\n  sigmoid: {\n    fn:   x => 1 / (1 + Math.exp(-x)),\n    deriv: x => { const s = 1 / (1 + Math.exp(-x)); return s * (1 - s); }\n  },\n  tanh: {\n    fn:   x => Math.tanh(x),\n    deriv: x => 1 - Math.tanh(x) ** 2\n  },\n  relu: {\n    fn:   x => Math.max(0, x),\n    deriv: x => x > 0 ? 1 : 0\n  }\n};\n\n// ── Neural Network ──\nclass NeuralNetwork {\n  constructor(hiddenSize, actKey) {\n    this.hiddenSize = hiddenSize;\n    this.actKey = actKey;\n    this.init();\n  }\n\n  init() {\n    const h = this.hiddenSize;\n    // Xavier init\n    const xav = (n) => (Math.random() * 2 - 1) * Math.sqrt(2 / n);\n    this.W1 = Array.from({ length: h }, () => [xav(2), xav(2)]);\n    this.b1 = Array(h).fill(0);\n    this.W2 = Array.from({ length: 1 }, () => Array.from({ length: h }, () => xav(h)));\n    this.b2 = [0];\n    // For animation\n    this.hiddenActivations = Array(h).fill(0);\n    this.outputActivation = 0;\n    this.inputActivations = [0, 0];\n  }\n\n  forward(input) {\n    const act = activations[this.actKey];\n    // Hidden layer\n    this.z1 = this.W1.map((row, i) =>\n      row.reduce((sum, w, j) => sum + w * input[j], 0) + this.b1[i]\n    );\n    this.a1 = this.z1.map(z => act.fn(z));\n\n    // Output layer (always sigmoid for classification)\n    this.z2 = this.W2.map(row =>\n      row.reduce((sum, w, j) => sum + w * this.a1[j], 0)\n    ).map((z, i) => z + this.b2[i]);\n    this.a2 = this.z2.map(z => activations.sigmoid.fn(z));\n\n    return this.a2[0];\n  }\n\n  backward(input, target, lr) {\n    const act = activations[this.actKey];\n    const h = this.hiddenSize;\n    const pred = this.a2[0];\n    // Output error\n    const dOut = pred - target;\n    // W2 gradients\n    const dW2 = this.W2.map((row, i) => row.map((_, j) => dOut * this.a1[j]));\n    const db2 = [dOut];\n    // Hidden error\n    const dHidden = this.a1.map((_, j) =>\n      dOut * this.W2[0][j] * act.deriv(this.z1[j])\n    );\n    // W1 gradients\n    const dW1 = this.W1.map((row, i) => row.map((_, j) => dHidden[i] * input[j]));\n    const db1 = dHidden.slice();\n    // Update\n    this.W2 = this.W2.map((row, i) => row.map((w, j) => w - lr * dW2[i][j]));\n    this.b2 = this.b2.map((b, i) => b - lr * db2[i]);\n    this.W1 = this.W1.map((row, i) => row.map((w, j) => w - lr * dW1[i][j]));\n    this.b1 = this.b1.map((b, i) => b - lr * db1[i]);\n  }\n\n  trainEpoch(lr) {\n    let loss = 0;\n    for (const sample of XOR_DATA) {\n      const pred = this.forward(sample.input);\n      loss += 0.5 * (pred - sample.target) ** 2;\n      this.backward(sample.input, sample.target, lr);\n    }\n    return loss / XOR_DATA.length;\n  }\n\n  predict(input) {\n    return this.forward(input);\n  }\n\n  getPredictions() {\n    return XOR_DATA.map(d => ({\n      input: d.input,\n      target: d.target,\n      pred: this.forward(d.input)\n    }));\n  }\n}\n\n// ── State ──\nlet nn, epoch, losses, isRunning, animFrame, lastForward, lastInput;\nlet trainInterval = null;\n\nfunction getHiddenSize() { return parseInt(document.getElementById('hidden-slider').value); }\nfunction getLR()         { return parseFloat(document.getElementById('lr-slider').value); }\nfunction getActKey()     { return document.getElementById('activation-select').value; }\nfunction getSpeed()      { return parseInt(document.getElementById('speed-slider').value); }\n\nfunction resetNetwork() {\n  stopTraining();\n  epoch = 0;\n  losses = [];\n  nn = new NeuralNetwork(getHiddenSize(), getActKey());\n  lastForward = null;\n  updateStats();\n  updateTruthTable();\n  updateActivationPills();\n  drawNetwork(null);\n  drawBoundary();\n  resetChart();\n  document.getElementById('btn-train').innerHTML = '<i data-lucide=\"play\"></i> Train';\n  document.getElementById('btn-train').classList.remove('running');\n  lucide.createIcons();\n}\n\n// ── Loss Chart ──\nlet lossChart;\nfunction initChart() {\n  const ctx = document.getElementById('loss-chart').getContext('2d');\n  lossChart = new Chart(ctx, {\n    type: 'line',\n    data: {\n      labels: [],\n      datasets: [{\n        label: 'MSE Loss',\n        data: [],\n        borderColor: '#00e5a0',\n        backgroundColor: 'rgba(0,229,160,0.08)',\n        borderWidth: 2,\n        pointRadius: 0,\n        fill: true,\n        tension: 0.4,\n      }]\n    },\n    options: {\n      responsive: true,\n      maintainAspectRatio: false,\n      animation: false,\n      plugins: {\n        legend: { display: false },\n        tooltip: {\n          mode: 'index',\n          intersect: false,\n          backgroundColor: '#1a1f2e',\n          borderColor: '#252b3b',\n          borderWidth: 1,\n          titleColor: '#6b7599',\n          bodyColor: '#e8eaf0',\n          titleFont: { family: 'JetBrains Mono', size: 10 },\n          bodyFont: { family: 'JetBrains Mono', size: 11 },\n        }\n      },\n      scales: {\n        x: {\n          ticks: {\n            color: '#6b7599',\n            font: { family: 'JetBrains Mono', size: 9 },\n            maxTicksLimit: 8\n          },\n          grid: { color: 'rgba(37,43,59,0.7)' }\n        },\n        y: {\n          ticks: {\n            color: '#6b7599',\n            font: { family: 'JetBrains Mono', size: 9 },\n          },\n          grid: { color: 'rgba(37,43,59,0.7)' },\n          min: 0\n        }\n      }\n    }\n  });\n}\n\nfunction resetChart() {\n  lossChart.data.labels = [];\n  lossChart.data.datasets[0].data = [];\n  lossChart.update();\n}\n\nfunction pushLoss(ep, loss) {\n  if (ep % 10 === 0 || ep < 10) {\n    lossChart.data.labels.push(ep);\n    lossChart.data.datasets[0].data.push(loss.toFixed(5));\n    lossChart.update();\n  }\n}\n\n// ── Stats ──\nfunction updateStats(loss) {\n  document.getElementById('stat-epoch').textContent = epoch;\n  document.getElementById('stat-loss').textContent = loss !== undefined ? loss.toFixed(5) : '—';\n  const preds = nn.getPredictions();\n  const correct = preds.filter(p => Math.round(p.pred) === p.target).length;\n  document.getElementById('stat-acc').textContent = loss !== undefined\n    ? `${correct}/4`\n    : '—';\n}\n\n// ── Truth Table ──\nfunction updateTruthTable() {\n  const preds = nn.getPredictions();\n  const ids = ['00', '01', '10', '11'];\n  preds.forEach((p, i) => {\n    const predEl  = document.getElementById(`pred-${ids[i]}`);\n    const verdEl  = document.getElementById(`verd-${ids[i]}`);\n    predEl.textContent = p.pred.toFixed(3);\n    const correct = Math.round(p.pred) === p.target;\n    verdEl.className = 'verdict ' + (correct ? 'ok' : 'bad');\n  });\n}\n\n// ── Activation Pills ──\nfunction updateActivationPills() {\n  const preds = nn.getPredictions();\n  const ids = ['00', '01', '10', '11'];\n  const targets = [0, 1, 1, 0];\n  preds.forEach((p, i) => {\n    const pill = document.getElementById(`act-${ids[i]}`);\n    const out  = document.getElementById(`out-${ids[i]}`);\n    out.textContent = p.pred.toFixed(3);\n    const correct = Math.round(p.pred) === p.target;\n    pill.className = 'activation-pill ' + (correct ? 'correct' : 'wrong');\n  });\n}\n\n// ── Network Canvas ──\nconst NET_CANVAS = document.getElementById('network-canvas');\nconst NET_CTX = NET_CANVAS.getContext('2d');\n\nfunction getNeuronPositions(hiddenSize) {\n  const W = NET_CANVAS.width;\n  const H = NET_CANVAS.height;\n  const cols = [W * 0.13, W * 0.42, W * 0.78];\n  const layers = [2, hiddenSize, 1];\n  return layers.map((count, li) => {\n    const x = cols[li];\n    return Array.from({ length: count }, (_, i) => ({\n      x,\n      y: H / 2 + (i - (count - 1) / 2) * Math.min(68, (H - 40) / count)\n    }));\n  });\n}\n\nfunction clamp01(v) { return Math.max(0, Math.min(1, v)); }\nfunction lerpColor(a, b, t) {\n  const hex = (s) => parseInt(s, 16);\n  const parse = c => ({ r: hex(c.slice(1,3)), g: hex(c.slice(3,5)), b: hex(c.slice(5,7)) });\n  const ca = parse(a), cb = parse(b);\n  const r = Math.round(ca.r + (cb.r - ca.r) * t);\n  const g = Math.round(ca.g + (cb.g - ca.g) * t);\n  const b2 = Math.round(ca.b + (cb.b - ca.b) * t);\n  return `rgb(${r},${g},${b2})`;\n}\n\nfunction drawNetwork(forward) {\n  const ctx = NET_CTX;\n  const W = NET_CANVAS.width;\n  const H = NET_CANVAS.height;\n  ctx.clearRect(0, 0, W, H);\n\n  // Background\n  ctx.fillStyle = '#12151d';\n  ctx.fillRect(0, 0, W, H);\n\n  const hiddenSize = nn.hiddenSize;\n  const positions = getNeuronPositions(hiddenSize);\n\n  // Extract weights for edge color\n  const W1 = nn.W1; // [hidden x 2]\n  const W2 = nn.W2; // [1 x hidden]\n  const maxW1 = W1.flat().reduce((m, v) => Math.max(m, Math.abs(v)), 0.001);\n  const maxW2 = W2.flat().reduce((m, v) => Math.max(m, Math.abs(v)), 0.001);\n\n  // Draw edges input → hidden\n  for (let i = 0; i < hiddenSize; i++) {\n    for (let j = 0; j < 2; j++) {\n      const w = W1[i][j];\n      const t = clamp01((w + maxW1) / (2 * maxW1));\n      const col = w > 0 ? `rgba(0,229,160,${0.15 + 0.55 * Math.abs(w) / maxW1})`\n                        : `rgba(255,107,107,${0.15 + 0.55 * Math.abs(w) / maxW1})`;\n      drawEdge(ctx, positions[0][j], positions[1][i], col, Math.max(0.5, 2.5 * Math.abs(w) / maxW1));\n    }\n  }\n\n  // Draw edges hidden → output\n  for (let j = 0; j < hiddenSize; j++) {\n    const w = W2[0][j];\n    const col = w > 0 ? `rgba(0,229,160,${0.15 + 0.55 * Math.abs(w) / maxW2})`\n                      : `rgba(255,107,107,${0.15 + 0.55 * Math.abs(w) / maxW2})`;\n    drawEdge(ctx, positions[1][j], positions[2][0], col, Math.max(0.5, 2.5 * Math.abs(w) / maxW2));\n  }\n\n  // Get activations for color\n  let inputActs = [0.5, 0.5];\n  let hidActs = Array(hiddenSize).fill(0.5);\n  let outAct = 0.5;\n\n  if (forward) {\n    inputActs = forward.input;\n    hidActs = forward.a1;\n    outAct = forward.a2;\n  }\n\n  // Draw neurons — input\n  const layerLabels = [['x₁', 'x₂'],\n    Array.from({ length: hiddenSize }, (_, i) => `h${i + 1}`),\n    ['ŷ']];\n\n  positions.forEach((layer, li) => {\n    layer.forEach((pos, ni) => {\n      let act = 0.5;\n      if (li === 0) act = inputActs[ni];\n      if (li === 1) act = clamp01(hidActs[ni]);\n      if (li === 2) act = clamp01(outAct);\n\n      drawNeuron(ctx, pos.x, pos.y, act, layerLabels[li][ni], li);\n    });\n  });\n\n  // Layer labels\n  const layerNames = ['Input', 'Hidden', 'Output'];\n  [0, 1, 2].forEach(li => {\n    ctx.font = '10px JetBrains Mono';\n    ctx.fillStyle = '#6b7599';\n    ctx.textAlign = 'center';\n    const x = positions[li][0].x;\n    ctx.fillText(layerNames[li], x, H - 8);\n  });\n}\n\nfunction drawEdge(ctx, from, to, color, width) {\n  ctx.beginPath();\n  ctx.moveTo(from.x, from.y);\n  // Bezier curve\n  const cx = (from.x + to.x) / 2;\n  ctx.bezierCurveTo(cx, from.y, cx, to.y, to.x, to.y);\n  ctx.strokeStyle = color;\n  ctx.lineWidth = width;\n  ctx.stroke();\n}\n\nfunction drawNeuron(ctx, x, y, activation, label, layerIdx) {\n  const r = layerIdx === 2 ? 20 : 16;\n  // Glow\n  const glowColor = activation > 0.5\n    ? `rgba(0,229,160,${0.15 + 0.55 * activation})`\n    : `rgba(76,201,240,${0.1 + 0.3 * (1 - activation)})`;\n  ctx.shadowBlur = 14 * activation;\n  ctx.shadowColor = glowColor;\n\n  // Neuron body\n  const grad = ctx.createRadialGradient(x - r * 0.3, y - r * 0.3, r * 0.1, x, y, r);\n  grad.addColorStop(0, lerpColor('#2a3a4a', '#00e5a0', clamp01(activation)));\n  grad.addColorStop(1, '#12151d');\n\n  ctx.beginPath();\n  ctx.arc(x, y, r, 0, Math.PI * 2);\n  ctx.fillStyle = grad;\n  ctx.fill();\n  ctx.shadowBlur = 0;\n\n  // Border\n  ctx.strokeStyle = activation > 0.5\n    ? `rgba(0,229,160,${0.4 + 0.6 * activation})`\n    : '#252b3b';\n  ctx.lineWidth = 1.5;\n  ctx.stroke();\n\n  // Label\n  ctx.font = `bold ${r > 18 ? 11 : 9}px JetBrains Mono`;\n  ctx.fillStyle = '#e8eaf0';\n  ctx.textAlign = 'center';\n  ctx.textBaseline = 'middle';\n  ctx.fillText(label, x, y);\n}\n\n// ── Decision Boundary ──\nconst BOUND_CANVAS = document.getElementById('boundary-canvas');\nconst BOUND_CTX = BOUND_CANVAS.getContext('2d');\nconst BOUND_SIZE = 80; // internal resolution\n\nfunction drawBoundary() {\n  const size = BOUND_SIZE;\n  const imgData = BOUND_CTX.createImageData(size, size);\n  for (let row = 0; row < size; row++) {\n    for (let col = 0; col < size; col++) {\n      const x1 = col / (size - 1);\n      const x2 = 1 - row / (size - 1);\n      const pred = nn.predict([x1, x2]);\n      const idx = (row * size + col) * 4;\n      if (pred > 0.5) {\n        // Green tint\n        imgData.data[idx]     = Math.round(0  + pred * 0);\n        imgData.data[idx + 1] = Math.round(80 + pred * 100);\n        imgData.data[idx + 2] = Math.round(50 + pred * 50);\n        imgData.data[idx + 3] = Math.round(80 + pred * 120);\n      } else {\n        // Red tint\n        imgData.data[idx]     = Math.round(120 + (1 - pred) * 100);\n        imgData.data[idx + 1] = Math.round(20);\n        imgData.data[idx + 2] = Math.round(20);\n        imgData.data[idx + 3] = Math.round(80 + (1 - pred) * 100);\n      }\n    }\n  }\n\n  // Render image at full canvas size\n  const tmpCanvas = document.createElement('canvas');\n  tmpCanvas.width = size;\n  tmpCanvas.height = size;\n  tmpCanvas.getContext('2d').putImageData(imgData, 0, 0);\n  BOUND_CTX.fillStyle = '#12151d';\n  BOUND_CTX.fillRect(0, 0, BOUND_CANVAS.width, BOUND_CANVAS.height);\n  BOUND_CTX.imageSmoothingEnabled = false;\n  BOUND_CTX.drawImage(tmpCanvas, 0, 0, BOUND_CANVAS.width, BOUND_CANVAS.height);\n\n  // Draw XOR points\n  const pts = [\n    { x: 0, y: 0, t: 0 },\n    { x: 0, y: 1, t: 1 },\n    { x: 1, y: 0, t: 1 },\n    { x: 1, y: 1, t: 0 },\n  ];\n  pts.forEach(p => {\n    const cx = p.x * (BOUND_CANVAS.width - 24) + 12;\n    const cy = (1 - p.y) * (BOUND_CANVAS.height - 24) + 12;\n    BOUND_CTX.beginPath();\n    BOUND_CTX.arc(cx, cy, 7, 0, Math.PI * 2);\n    BOUND_CTX.fillStyle = p.t === 1 ? '#00e5a0' : '#ff6b6b';\n    BOUND_CTX.fill();\n    BOUND_CTX.strokeStyle = '#0c0e13';\n    BOUND_CTX.lineWidth = 2;\n    BOUND_CTX.stroke();\n  });\n}\n\n// ── Training Loop ──\nfunction runEpochs(count) {\n  for (let i = 0; i < count; i++) {\n    const loss = nn.trainEpoch(getLR());\n    epoch++;\n    losses.push(loss);\n    pushLoss(epoch, loss);\n\n    if (i === count - 1) {\n      updateStats(loss);\n      updateTruthTable();\n      updateActivationPills();\n\n      // Do a forward pass on a random XOR sample for animation\n      const sample = XOR_DATA[Math.floor(Math.random() * 4)];\n      nn.forward(sample.input);\n      drawNetwork({ input: sample.input, a1: nn.a1, a2: nn.a2[0] });\n      drawBoundary();\n    }\n  }\n}\n\nfunction startTraining() {\n  if (isRunning) return;\n  isRunning = true;\n  document.getElementById('btn-train').innerHTML = '<i data-lucide=\"pause\"></i> Pause';\n  document.getElementById('btn-train').classList.add('running');\n  lucide.createIcons();\n\n  function loop() {\n    if (!isRunning) return;\n    runEpochs(getSpeed());\n    animFrame = requestAnimationFrame(loop);\n  }\n  animFrame = requestAnimationFrame(loop);\n}\n\nfunction stopTraining() {\n  isRunning = false;\n  if (animFrame) cancelAnimationFrame(animFrame);\n  document.getElementById('btn-train').innerHTML = '<i data-lucide=\"play\"></i> Train';\n  document.getElementById('btn-train').classList.remove('running');\n  lucide.createIcons();\n}\n\n// ── Event Listeners ──\ndocument.getElementById('btn-train').addEventListener('click', () => {\n  if (isRunning) stopTraining(); else startTraining();\n});\n\ndocument.getElementById('btn-step').addEventListener('click', () => {\n  stopTraining();\n  runEpochs(1);\n});\n\ndocument.getElementById('btn-reset').addEventListener('click', resetNetwork);\n\ndocument.getElementById('lr-slider').addEventListener('input', function () {\n  document.getElementById('lr-val').textContent = parseFloat(this.value).toFixed(3);\n});\n\ndocument.getElementById('hidden-slider').addEventListener('input', function () {\n  document.getElementById('hidden-val').textContent = this.value;\n  // Rebuild network immediately\n  resetNetwork();\n  document.getElementById('hidden-val').textContent = this.value;\n});\n\ndocument.getElementById('activation-select').addEventListener('change', () => {\n  resetNetwork();\n});\n\ndocument.getElementById('speed-slider').addEventListener('input', function () {\n  document.getElementById('speed-val').textContent = this.value + '×';\n});\n\n// ── Init ──\ninitChart();\nresetNetwork();\nlucide.createIcons();\n"},{"name":"style.css","content":"/* ── Reset & Base ── */\n*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n:root {\n  --bg: #0c0e13;\n  --surface: #12151d;\n  --surface2: #1a1f2e;\n  --border: #252b3b;\n  --accent: #00e5a0;\n  --accent2: #ff6b6b;\n  --accent3: #ffd166;\n  --accent4: #4cc9f0;\n  --text: #e8eaf0;\n  --text-muted: #8e9bbf;\n  --font-mono: 'JetBrains Mono', monospace;\n  --font-ui: 'Inter', sans-serif;\n  color-scheme: dark;\n}\n\nbody {\n  background: var(--bg);\n  color: var(--text);\n  font-family: var(--font-ui);\n  min-height: 100vh;\n  overflow-x: hidden;\n}\n\n/* ── Header ── */\n.header {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 0.85rem 1.5rem;\n  background: var(--surface);\n  border-bottom: 1px solid var(--border);\n  position: sticky;\n  top: 0;\n  z-index: 10;\n}\n\n.header__logo {\n  display: flex;\n  align-items: center;\n  gap: 0.6rem;\n  font-family: var(--font-mono);\n  font-weight: 700;\n  font-size: 1rem;\n  letter-spacing: -0.01em;\n  color: var(--accent);\n}\n\n.header__logo svg { width: 22px; height: 22px; stroke: var(--accent); }\n\n.header__badge {\n  font-family: var(--font-mono);\n  font-size: 0.7rem;\n  padding: 0.2rem 0.7rem;\n  border-radius: 999px;\n  background: color-mix(in srgb, var(--accent) 12%, transparent);\n  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);\n  color: var(--accent);\n  letter-spacing: 0.05em;\n}\n\n/* ── Main Layout ── */\n.main {\n  display: grid;\n  grid-template-columns: 1fr 280px 280px;\n  gap: 1rem;\n  padding: 1rem;\n  min-height: calc(100vh - 56px);\n  align-items: start;\n}\n\n/* ── Panel ── */\n.panel {\n  background: var(--surface);\n  border: 1px solid var(--border);\n  border-radius: 14px;\n  padding: 1.1rem 1.1rem;\n  display: flex;\n  flex-direction: column;\n  gap: 0.85rem;\n}\n\n.panel__header {\n  display: flex;\n  align-items: center;\n  gap: 0.5rem;\n  color: var(--text-muted);\n  font-size: 0.8rem;\n  font-weight: 600;\n  text-transform: uppercase;\n  letter-spacing: 0.06em;\n}\n\n.panel__header svg { width: 15px; height: 15px; }\n.panel__header h2 { font-size: 0.8rem; font-weight: 600; color: var(--text-muted); }\n.panel__sub {\n  font-family: var(--font-mono);\n  font-size: 0.7rem;\n  margin-left: auto;\n  color: var(--accent);\n  background: color-mix(in srgb, var(--accent) 10%, transparent);\n  padding: 0.15rem 0.5rem;\n  border-radius: 4px;\n}\n\n/* ── Network Canvas ── */\n#network-canvas {\n  width: 100%;\n  height: auto;\n  border-radius: 10px;\n  background: var(--surface2);\n  border: 1px solid var(--border);\n  display: block;\n}\n\n/* ── Activation Pills ── */\n.activations-row {\n  display: grid;\n  grid-template-columns: 1fr 1fr;\n  gap: 0.5rem;\n}\n\n.activation-pill {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  padding: 0.4rem 0.7rem;\n  background: var(--surface2);\n  border: 1px solid var(--border);\n  border-radius: 8px;\n  font-size: 0.72rem;\n  transition: border-color 0.3s;\n}\n\n.activation-pill.correct { border-color: var(--accent); }\n.activation-pill.wrong   { border-color: var(--accent2); }\n\n.act-label { font-family: var(--font-mono); color: var(--text-muted); }\n.act-output { font-family: var(--font-mono); font-weight: 700; color: var(--accent4); }\n\n/* ── Controls ── */\n.controls-grid {\n  display: flex;\n  flex-direction: column;\n  gap: 0.75rem;\n}\n\n.control-group {\n  display: flex;\n  flex-direction: column;\n  gap: 0.3rem;\n}\n\n.control-group label {\n  font-size: 0.75rem;\n  color: var(--text-muted);\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.mono { font-family: var(--font-mono); color: var(--text); }\n\ninput[type=\"range\"] {\n  -webkit-appearance: none;\n  appearance: none;\n  width: 100%;\n  height: 4px;\n  border-radius: 99px;\n  background: var(--surface2);\n  outline: none;\n  cursor: pointer;\n}\n\ninput[type=\"range\"]::-webkit-slider-thumb {\n  -webkit-appearance: none;\n  width: 14px;\n  height: 14px;\n  border-radius: 50%;\n  background: var(--accent);\n  border: 2px solid var(--bg);\n  box-shadow: 0 0 8px var(--accent);\n  cursor: pointer;\n  transition: transform 0.15s;\n}\n\ninput[type=\"range\"]::-webkit-slider-thumb:hover { transform: scale(1.25); }\n\nselect {\n  width: 100%;\n  padding: 0.45rem 0.7rem;\n  border-radius: 8px;\n  border: 1px solid var(--border);\n  background: var(--surface2);\n  color: var(--text);\n  font-family: var(--font-mono);\n  font-size: 0.78rem;\n  outline: none;\n  cursor: pointer;\n}\n\nselect:focus { border-color: var(--accent); }\n\n/* ── Buttons ── */\n.btn-row {\n  display: flex;\n  gap: 0.5rem;\n}\n\n.btn {\n  display: flex;\n  align-items: center;\n  gap: 0.4rem;\n  padding: 0.5rem 0.9rem;\n  border-radius: 8px;\n  border: none;\n  font-family: var(--font-mono);\n  font-size: 0.75rem;\n  font-weight: 600;\n  cursor: pointer;\n  transition: all 0.18s;\n  flex: 1;\n  justify-content: center;\n}\n\n.btn svg { width: 13px; height: 13px; }\n\n.btn--primary {\n  background: var(--accent);\n  color: #0c0e13;\n}\n\n.btn--primary:hover { filter: brightness(1.15); box-shadow: 0 0 18px color-mix(in srgb, var(--accent) 50%, transparent); }\n.btn--primary.running { background: var(--accent3); }\n\n.btn--ghost {\n  background: var(--surface2);\n  color: var(--text);\n  border: 1px solid var(--border);\n}\n\n.btn--ghost:hover { border-color: var(--accent4); color: var(--accent4); }\n\n.btn--danger {\n  background: var(--surface2);\n  color: var(--accent2);\n  border: 1px solid color-mix(in srgb, var(--accent2) 30%, transparent);\n}\n\n.btn--danger:hover { background: color-mix(in srgb, var(--accent2) 15%, transparent); }\n\n/* ── Stats Bar ── */\n.stats-bar {\n  display: flex;\n  gap: 0.5rem;\n}\n\n.stat {\n  flex: 1;\n  background: var(--surface2);\n  border: 1px solid var(--border);\n  border-radius: 8px;\n  padding: 0.5rem 0.6rem;\n  text-align: center;\n}\n\n.stat__label {\n  display: block;\n  font-size: 0.65rem;\n  color: var(--text-muted);\n  text-transform: uppercase;\n  letter-spacing: 0.07em;\n  margin-bottom: 0.2rem;\n}\n\n.stat__value {\n  font-size: 0.9rem;\n  font-weight: 700;\n  color: var(--accent);\n}\n\n/* ── Decision Boundary ── */\n#boundary-canvas {\n  width: 100%;\n  height: auto;\n  border-radius: 10px;\n  border: 1px solid var(--border);\n  display: block;\n  image-rendering: pixelated;\n}\n\n.legend-row {\n  display: flex;\n  align-items: center;\n  gap: 0.6rem;\n  font-size: 0.72rem;\n  color: var(--text-muted);\n}\n\n.legend-dot {\n  width: 10px; height: 10px;\n  border-radius: 50%;\n  display: inline-block;\n  margin-left: 0.5rem;\n}\n\n.legend-dot--zero { background: var(--accent2); box-shadow: 0 0 6px var(--accent2); }\n.legend-dot--one  { background: var(--accent); box-shadow: 0 0 6px var(--accent); }\n\n/* ── Loss Chart ── */\n.chart-wrap {\n  background: var(--surface2);\n  border: 1px solid var(--border);\n  border-radius: 10px;\n  padding: 0.8rem;\n  height: 180px;\n  position: relative;\n}\n\n.chart-wrap canvas { width: 100% !important; height: 100% !important; }\n\n/* ── Truth Table ── */\n.truth-table {\n  width: 100%;\n  border-collapse: collapse;\n  font-size: 0.75rem;\n  font-family: var(--font-mono);\n}\n\n.truth-table th {\n  text-align: center;\n  padding: 0.4rem 0.3rem;\n  color: var(--text-muted);\n  font-size: 0.65rem;\n  text-transform: uppercase;\n  letter-spacing: 0.06em;\n  border-bottom: 1px solid var(--border);\n}\n\n.truth-table td {\n  text-align: center;\n  padding: 0.45rem 0.3rem;\n  border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);\n  transition: color 0.3s;\n}\n\n.truth-table tr:last-child td { border-bottom: none; }\n\n.truth-table .pred { font-weight: 700; color: var(--accent4); }\n\n.verdict {\n  font-size: 1rem;\n}\n\n.verdict.ok::after  { content: '✓'; color: var(--accent); }\n.verdict.bad::after { content: '✗'; color: var(--accent2); }\n\n/* ── Speed Control ── */\n.speed-control {\n  display: flex;\n  align-items: center;\n  gap: 0.6rem;\n  font-size: 0.72rem;\n  color: var(--text-muted);\n}\n\n.speed-control svg { width: 13px; height: 13px; stroke: var(--accent3); }\n.speed-control label { display: flex; align-items: center; gap: 0.4rem; white-space: nowrap; }\n.speed-control input { flex: 1; }\n.speed-control .mono { font-size: 0.72rem; min-width: 2.5rem; text-align: right; }\n\n/* ── Animations ── */\n@keyframes pulse-glow {\n  0%, 100% { box-shadow: 0 0 6px var(--accent); }\n  50% { box-shadow: 0 0 18px var(--accent); }\n}\n\n.stat__value.animated { animation: pulse-glow 0.6s ease; }\n\n@keyframes fadeSlideIn {\n  from { opacity: 0; transform: translateY(6px); }\n  to   { opacity: 1; transform: translateY(0); }\n}\n\n.panel { animation: fadeSlideIn 0.4s ease both; }\n.panel--controls { animation-delay: 0.05s; }\n.panel--chart    { animation-delay: 0.1s; }\n\n/* ── Responsive ── */\n@media (max-width: 900px) {\n  .main {\n    grid-template-columns: 1fr;\n  }\n}\n"}],"folders":[]},"variants":null,"createdAt":"2026-04-09T01:46:19.943Z","updatedAt":"2026-04-09T01:46:22.897Z"}}