{"claude_md":"# Git Graph Visualizer\n\nAnimated canvas visualization of a realistic git branch history: 4 branches, 13 commits, merge commits, HEAD glow, and smooth auto-scroll. Pure HTML5 canvas.\n\n## Quick Reference\n\nSee skill files — primary content is `git-graph.html`.\n\n## Agent Docs (read when relevant)\n\n| File | When to read |\n|------|-------------|\n| `agent_docs/git-graph.html` | git graph |\n| `agent_docs/README.md` | README |\n","agent_docs":{"agent_docs/git-graph.html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Git Graph Visualizer</title>\n<style>\n* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { background: #0a0a1a; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: monospace; }\ncanvas { border-radius: 12px; box-shadow: 0 0 60px rgba(168,85,247,0.15); }\n</style>\n</head>\n<body>\n<canvas id=\"c\"></canvas>\n<script>\nconst C = document.getElementById('c');\nC.width = 800; C.height = 500;\nconst ctx = C.getContext('2d');\nconst W = 800, H = 500;\n\n// Branch lanes (y positions)\nconst LANE = { main: 80, feat_auth: 180, feat_ui: 280, hotfix: 130 };\nconst COLOR = { main: '#a855f7', feat_auth: '#06b6d4', feat_ui: '#10b981', hotfix: '#f43f5e' };\nconst LABEL = { main: 'main', feat_auth: 'feature/auth', feat_ui: 'feature/ui', hotfix: 'hotfix/crash' };\n\nfunction rh() { return Math.random().toString(16).substr(2,7); }\n\n// Build git history — right = older, left = newer\n// Each commit: { id, branch, x, y, msg, color, merge }\nconst STEP = 90;\nlet commits = [];\nlet edges = []; // { from_id, to_id }\n\nfunction commit(branch, msg, parents, merge) {\n  const x = 730 - commits.length * STEP;\n  const c = { id: rh(), branch, x, y: LANE[branch], msg, color: COLOR[branch], merge: !!merge };\n  commits.push(c);\n  (parents||[]).forEach(p => edges.push({ f: p, t: c.id }));\n  return c.id;\n}\n\n// Build a realistic git history\nconst c0  = commit('main',      'init: project scaffold',  []);\nconst c1  = commit('main',      'feat: add routing',       [c0]);\nconst c2  = commit('feat_auth', 'feat: JWT middleware',    [c1]);\nconst c3  = commit('main',      'docs: update README',     [c1]);\nconst c4  = commit('hotfix',    'fix: null ptr crash',     [c3]);\nconst c5  = commit('feat_auth', 'feat: refresh tokens',    [c2]);\nconst c6  = commit('main',      'merge: hotfix',           [c3, c4], true);\nconst c7  = commit('feat_ui',   'feat: hero section',      [c6]);\nconst c8  = commit('feat_auth', 'test: auth coverage',     [c5]);\nconst c9  = commit('feat_ui',   'feat: navbar responsive', [c7]);\nconst c10 = commit('main',      'merge: feature/auth',     [c6, c8], true);\nconst c11 = commit('feat_ui',   'feat: dark mode toggle',  [c9]);\nconst c12 = commit('main',      'merge: feature/ui',       [c10, c11], true);\nconst c13 = commit('main',      'chore: bump v1.2.0',      [c12]);\n\n// Animation state\nlet offset = 0;\nlet pulse = 0;\nlet frame = 0;\n\nfunction getC(id) { return commits.find(c => c.id === id); }\n\nfunction drawLaneLines() {\n  Object.entries(LANE).forEach(([k, y]) => {\n    ctx.save();\n    ctx.setLineDash([5, 12]);\n    ctx.strokeStyle = COLOR[k] + '18';\n    ctx.lineWidth = 1;\n    ctx.beginPath(); ctx.moveTo(60, y); ctx.lineTo(W - 10, y); ctx.stroke();\n    ctx.restore();\n    ctx.fillStyle = COLOR[k];\n    ctx.font = 'bold 11px monospace';\n    ctx.textAlign = 'left';\n    ctx.fillText(LABEL[k], 8, y + 4);\n  });\n}\n\nfunction drawEdge(e) {\n  const f = getC(e.f), t = getC(e.t);\n  if (!f || !t) return;\n  const fx = f.x + offset, tx = t.x + offset;\n  if (fx < 55 && tx < 55) return;\n  ctx.save();\n  ctx.strokeStyle = t.color + '99';\n  ctx.lineWidth = 2;\n  ctx.beginPath();\n  ctx.moveTo(fx, f.y);\n  if (f.y === t.y) {\n    ctx.lineTo(tx, t.y);\n  } else {\n    const mx = (fx + tx) / 2;\n    ctx.bezierCurveTo(mx, f.y, mx, t.y, tx, t.y);\n  }\n  ctx.stroke();\n  ctx.restore();\n}\n\nfunction drawCommit(c) {\n  const x = c.x + offset;\n  if (x < 55 || x > W - 5) return;\n  const r = c.merge ? 11 : 8;\n\n  // Glow for HEAD commit (c13)\n  if (c.id === c13) {\n    ctx.save();\n    ctx.shadowColor = c.color;\n    ctx.shadowBlur = 14 + Math.sin(pulse) * 5;\n    ctx.fillStyle = c.color;\n    ctx.beginPath(); ctx.arc(x, c.y, r + 2, 0, Math.PI*2); ctx.fill();\n    ctx.restore();\n  }\n\n  // Outer ring\n  ctx.fillStyle = c.color;\n  ctx.beginPath(); ctx.arc(x, c.y, r, 0, Math.PI*2); ctx.fill();\n\n  // Inner dot for merges\n  if (c.merge) {\n    ctx.fillStyle = '#0a0a1a';\n    ctx.beginPath(); ctx.arc(x, c.y, 5, 0, Math.PI*2); ctx.fill();\n    ctx.fillStyle = c.color;\n    ctx.beginPath(); ctx.arc(x, c.y, 2, 0, Math.PI*2); ctx.fill();\n  }\n\n  // Hash below\n  ctx.fillStyle = '#444';\n  ctx.font = '9px monospace';\n  ctx.textAlign = 'center';\n  ctx.fillText(c.id.slice(0,6), x, c.y + 22);\n\n  // Message above\n  ctx.fillStyle = c.color + 'cc';\n  ctx.font = '9.5px monospace';\n  const msg = c.msg.length > 20 ? c.msg.slice(0,19) + '…' : c.msg;\n  ctx.fillText(msg, x, c.y - 18);\n}\n\nfunction drawHUD() {\n  // Title\n  ctx.fillStyle = '#e2e8f0';\n  ctx.font = 'bold 15px monospace';\n  ctx.textAlign = 'left';\n  ctx.fillText('Git Graph Visualizer', 8, 22);\n\n  // Stats\n  ctx.fillStyle = '#555';\n  ctx.font = '11px monospace';\n  ctx.fillText(`${commits.length} commits · ${Object.keys(LANE).length} branches`, 8, 40);\n\n  // Legend\n  ctx.textAlign = 'right';\n  ctx.fillStyle = '#444';\n  ctx.font = '10px monospace';\n  ctx.fillText('● merge  ● commit  HEAD→', W - 8, H - 8);\n}\n\nfunction render(ts) {\n  frame++;\n  pulse = ts / 600;\n  offset -= 0.25; // slow scroll right-to-left\n\n  ctx.fillStyle = '#0a0a1a';\n  ctx.fillRect(0, 0, W, H);\n\n  // Clip label area\n  ctx.save();\n  ctx.rect(60, 0, W, H);\n  ctx.clip();\n\n  drawLaneLines();\n  edges.forEach(drawEdge);\n  commits.forEach(drawCommit);\n  ctx.restore();\n\n  drawHUD();\n  requestAnimationFrame(render);\n}\n\nrequestAnimationFrame(render);\n</script>\n</body>\n</html>","agent_docs/README.md":"# Git Graph Visualizer\n\nAn animated canvas visualization of a realistic git repository history.\n\n## What it shows\n- **4 branches**: main (purple), feature/auth (cyan), feature/ui (green), hotfix (red)\n- **13 commits** in a realistic development timeline\n- **Merge commits** with double-ring styling\n- **HEAD commit** with pulsing glow effect\n- Slow auto-scroll animation (right = older, left = newer)\n\n## Visual elements\n- Dashed lane lines for each branch\n- Bezier curves for cross-branch edges\n- Abbreviated commit hashes below each node\n- Commit message labels above each node\n- Live frame counter\n\n## Built with\nPure HTML5 Canvas + requestAnimationFrame. Zero external dependencies.\n"}}