{"claude_md":"# Canvas Neural Network Visualizer\n\nAnimated neural network visualization with signal propagation, node activations, and weighted connections. Feed-forward architecture with sigmoid activation.\n\n## Quick Reference\n\n# Canvas Neural Network Visualizer\n\n> **Difficulty:** Intermediate | **Runtime:** HTML5 Canvas | **Output:** Animated visualization\n\nTeach an AI agent to visualize a feed-forward neural network with animated signal propagation, node activations, and weight connections.\n\n## What You'll Build\n\nA self-contained HTML file showing an animated neural network:\n- Configurable layer sizes (input → hidden → output)\n- Weighted connections drawn as lines (thickness = weight magnitude)\n- Signal pulses traveling along connections during forward pass\n- Node activation glow effect (brighter = higher activation)\n- Continuous forward pass animation with random inputs\n\n## Teaching Points\n\n- Neural network architecture visualization\n- Canvas arc drawing for nodes\n- Line thickness mapping for weight visualization\n- Particle/pulse animation along paths\n- Color interpolation for activation display\n\n## Agent Docs (read when relevant)\n\n| File | When to read |\n|------|-------------|\n| `agent_docs/neural-net.html` | neural net |\n| `agent_docs/README.md` | README |\n","agent_docs":{"agent_docs/neural-net.html":"<!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>Neural Network Visualizer</title>\n<style>\n  * { margin: 0; padding: 0; box-sizing: border-box; }\n  body { background: #0a0a1a; display: flex; justify-content: center; align-items: center; height: 100vh; flex-direction: column; }\n  canvas { border-radius: 12px; box-shadow: 0 0 40px rgba(168, 85, 247, 0.15); }\n  .title { color: #a855f7; font-family: monospace; font-size: 14px; margin-bottom: 12px; }\n</style>\n</head>\n<body>\n<div class=\"title\">Feed-Forward Neural Network — Forward Pass</div>\n<canvas id=\"c\"></canvas>\n<script>\nconst c = document.getElementById('c');\nconst W = c.width = 800, H = c.height = 500;\nconst ctx = c.getContext('2d');\n\nconst layers = [4, 6, 6, 3];\nconst nodeR = 16;\nconst layerColors = ['#06b6d4','#a855f7','#a855f7','#10b981'];\nconst labels = [['x₁','x₂','x₃','x₄'],null,null,['y₁','y₂','y₃']];\n\n// Build nodes\nconst nodes = [];\nconst padding = 80;\nlayers.forEach((size, li) => {\n  const x = padding + li * ((W - 2*padding) / (layers.length - 1));\n  const layerH = (size - 1) * 56;\n  const startY = (H - layerH) / 2;\n  for (let ni = 0; ni < size; ni++) {\n    nodes.push({ x, y: startY + ni * 56, layer: li, idx: ni, activation: 0, targetAct: 0 });\n  }\n});\n\n// Build connections with weights\nconst connections = [];\nnodes.forEach(n => {\n  if (n.layer < layers.length - 1) {\n    nodes.filter(m => m.layer === n.layer + 1).forEach(m => {\n      connections.push({ from: n, to: m, weight: (Math.random() - 0.5) * 2, pulses: [] });\n    });\n  }\n});\n\n// Signals\nlet signalTimer = 0;\n\nfunction newForwardPass() {\n  // Random input activations\n  nodes.filter(n => n.layer === 0).forEach(n => { n.targetAct = Math.random(); });\n  // Propagate through layers\n  for (let l = 1; l < layers.length; l++) {\n    nodes.filter(n => n.layer === l).forEach(n => {\n      let sum = 0;\n      connections.filter(c => c.to === n).forEach(c => {\n        sum += c.from.targetAct * c.weight;\n      });\n      n.targetAct = 1 / (1 + Math.exp(-sum)); // sigmoid\n    });\n  }\n  // Create pulses\n  connections.forEach(conn => {\n    conn.pulses.push({ t: 0, speed: 0.012 + Math.random() * 0.008 });\n  });\n}\n\nfunction lerp(a, b, t) { return a + (b - a) * t; }\n\nfunction render() {\n  ctx.fillStyle = '#0a0a1a';\n  ctx.fillRect(0, 0, W, H);\n\n  // Draw connections\n  connections.forEach(conn => {\n    const absW = Math.abs(conn.weight);\n    ctx.strokeStyle = conn.weight > 0 ? `rgba(16,185,129,${absW * 0.4})` : `rgba(244,63,94,${absW * 0.4})`;\n    ctx.lineWidth = absW * 2.5 + 0.3;\n    ctx.beginPath();\n    ctx.moveTo(conn.from.x, conn.from.y);\n    ctx.lineTo(conn.to.x, conn.to.y);\n    ctx.stroke();\n\n    // Draw pulses\n    conn.pulses = conn.pulses.filter(p => p.t <= 1);\n    conn.pulses.forEach(p => {\n      p.t += p.speed;\n      const px = lerp(conn.from.x, conn.to.x, p.t);\n      const py = lerp(conn.from.y, conn.to.y, p.t);\n      const glow = ctx.createRadialGradient(px, py, 0, px, py, 8);\n      glow.addColorStop(0, 'rgba(168,85,247,0.9)');\n      glow.addColorStop(1, 'rgba(168,85,247,0)');\n      ctx.fillStyle = glow;\n      ctx.beginPath();\n      ctx.arc(px, py, 8, 0, Math.PI * 2);\n      ctx.fill();\n    });\n  });\n\n  // Draw nodes\n  nodes.forEach(n => {\n    n.activation = lerp(n.activation, n.targetAct, 0.04);\n    const intensity = n.activation;\n    const color = layerColors[n.layer];\n\n    // Glow\n    const glow = ctx.createRadialGradient(n.x, n.y, nodeR * 0.5, n.x, n.y, nodeR * 2.5);\n    glow.addColorStop(0, color + Math.round(intensity * 60).toString(16).padStart(2, '0'));\n    glow.addColorStop(1, 'transparent');\n    ctx.fillStyle = glow;\n    ctx.beginPath();\n    ctx.arc(n.x, n.y, nodeR * 2.5, 0, Math.PI * 2);\n    ctx.fill();\n\n    // Node circle\n    ctx.beginPath();\n    ctx.arc(n.x, n.y, nodeR, 0, Math.PI * 2);\n    ctx.fillStyle = `rgba(10,10,26,0.8)`;\n    ctx.fill();\n    ctx.strokeStyle = color;\n    ctx.lineWidth = 2;\n    ctx.stroke();\n\n    // Inner fill based on activation\n    ctx.beginPath();\n    ctx.arc(n.x, n.y, nodeR - 3, 0, Math.PI * 2);\n    ctx.fillStyle = color + Math.round(intensity * 200).toString(16).padStart(2, '0');\n    ctx.fill();\n\n    // Label\n    const lbl = labels[n.layer]?.[n.idx];\n    if (lbl) {\n      ctx.fillStyle = '#ccc';\n      ctx.font = '11px monospace';\n      ctx.textAlign = 'center';\n      ctx.fillText(lbl, n.x, n.y + 30);\n    }\n\n    // Activation value\n    ctx.fillStyle = '#fff';\n    ctx.font = 'bold 9px monospace';\n    ctx.textAlign = 'center';\n    ctx.fillText(n.activation.toFixed(2), n.x, n.y + 4);\n  });\n  ctx.textAlign = 'left';\n\n  // Layer labels\n  const layerNames = ['Input', 'Hidden 1', 'Hidden 2', 'Output'];\n  layers.forEach((_, li) => {\n    const x = padding + li * ((W - 2*padding) / (layers.length - 1));\n    ctx.fillStyle = '#555';\n    ctx.font = '11px monospace';\n    ctx.textAlign = 'center';\n    ctx.fillText(layerNames[li], x, H - 20);\n  });\n  ctx.textAlign = 'left';\n\n  // Trigger new pass\n  signalTimer++;\n  if (signalTimer % 120 === 0) newForwardPass();\n\n  requestAnimationFrame(render);\n}\n\nnewForwardPass();\nrequestAnimationFrame(render);\n</script>\n</body>\n</html>","agent_docs/README.md":"# Neural Network Visualizer\n\nAnimated feed-forward neural network visualization with signal propagation.\n\n## Features\n- Configurable layer architecture (4→6→6→3)\n- Animated signal pulses traveling along weighted connections\n- Node activation glow based on sigmoid output\n- Color-coded positive (green) and negative (red) weights\n- Continuous forward pass with random inputs\n\n## Run\nOpen `neural-net.html` in any browser.\n"}}