{"manifest":{"name":"Canvas Data Dashboard","version":"1.0.0","description":"Animated real-time data dashboard with bar chart, line chart, donut chart, and live metrics. HTML5 Canvas, dark theme, 60fps.","tags":["canvas","visualization","dashboard","html"],"standard":"agentskills.io","standard_version":"1.0","content_checksum":"9da32e9b2dc4d62b6116ff94c0955c6c2f547abdd685cf4c0b6f2356032bde9a","bundle_checksum":"4dee93fa6a3133e90a3f9b6dd171473f7f26d2fe8ff5daf9ef2d88078852603c","metadata":{"runtime":{"language":"html","entrypoint":"dashboard.html","timeout_seconds":30},"dependencies":{"system":["browser"]}},"files":[{"path":"dashboard.html","name":"dashboard.html","mime_type":"text/html","checksum":"70b8c9843b66ddc1ed4781abd7fb123262c10cf44275b5a833973b8e0a48f059"},{"path":"README.md","name":"README.md","mime_type":"text/markdown","checksum":"b98d1a4eb543f5aeb174873467921a958a8a5659bffe1eb865a1323575307356"}]},"files":{"SKILL.md":"# Canvas Data Dashboard\n\n> **Difficulty:** Intermediate | **Runtime:** HTML5 Canvas | **Output:** Interactive visualization\n\nTeach an AI agent to generate a real-time animated data dashboard with multiple chart types, smooth transitions, and a dark theme.\n\n## What You'll Build\n\nA self-contained HTML file rendering an animated dashboard with:\n- Animated bar chart with value labels and smooth height transitions\n- Real-time line chart with scrolling data points\n- Donut/ring chart with percentage labels\n- FPS counter and live data feed simulation\n- Dark theme with neon accent colors\n\n## Core Concepts\n\n### 1. Canvas Rendering Pipeline\n\nThe dashboard uses a single `requestAnimationFrame` loop to render all charts:\n\n```javascript\nfunction render(timestamp) {\n  ctx.clearRect(0, 0, width, height);\n  drawBarChart(ctx, data.bars);\n  drawLineChart(ctx, data.timeSeries);\n  drawDonutChart(ctx, data.categories);\n  drawFPS(ctx, timestamp);\n  requestAnimationFrame(render);\n}\n```\n\n### 2. Smooth Transitions\n\nBar heights interpolate toward target values using lerp:\n\n```javascript\ncurrent += (target - current) * 0.08;  // ease toward target\n```\n\n### 3. Color Palette\n\nUse HSL with fixed saturation/lightness for consistent neon look:\n- Primary: `hsl(270, 80%, 65%)` — purple\n- Accent: `hsl(170, 80%, 55%)` — teal\n- Warn: `hsl(40, 90%, 60%)` — amber\n- Grid: `rgba(255,255,255,0.08)`\n\n## Teaching Points\n\n- Canvas coordinate system and transforms\n- `requestAnimationFrame` for 60fps rendering\n- Lerp-based animation for smooth transitions\n- Drawing arcs for donut charts\n- Text measurement and alignment on canvas","dashboard.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>Data Dashboard</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; }\n  canvas { border-radius: 12px; box-shadow: 0 0 40px rgba(168, 85, 247, 0.15); }\n</style>\n</head>\n<body>\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 colors = ['#a855f7','#06b6d4','#f59e0b','#10b981','#f43f5e','#6366f1'];\nconst barLabels = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];\nconst catLabels = ['API','Auth','UI','DB','Tests'];\n\nlet bars = barLabels.map(() => ({ val: 0, target: Math.random()*100 }));\nlet line = Array.from({length: 40}, () => Math.random()*60+20);\nlet cats = catLabels.map(() => Math.random()*40+10);\nlet frame = 0, lastTime = 0, fps = 0;\n\nfunction lerp(a,b,t){ return a+(b-a)*t; }\n\nfunction drawBars(){\n  const x0=40, y0=30, w=360, h=180;\n  ctx.fillStyle='#fff'; ctx.font='bold 13px monospace';\n  ctx.fillText('Weekly Requests (k)',x0,y0-8);\n  const bw=w/bars.length;\n  bars.forEach((b,i)=>{\n    b.val=lerp(b.val,b.target,0.06);\n    const bh=b.val/100*h;\n    const grad=ctx.createLinearGradient(0,y0+h-bh,0,y0+h);\n    grad.addColorStop(0,colors[i%colors.length]);\n    grad.addColorStop(1,colors[i%colors.length]+'44');\n    ctx.fillStyle=grad;\n    ctx.fillRect(x0+i*bw+8,y0+h-bh,bw-16,bh);\n    ctx.fillStyle='#888'; ctx.font='10px monospace';\n    ctx.textAlign='center';\n    ctx.fillText(barLabels[i],x0+i*bw+bw/2,y0+h+14);\n    ctx.fillStyle='#fff'; ctx.font='bold 10px monospace';\n    ctx.fillText(Math.round(b.val)+'k',x0+i*bw+bw/2,y0+h-bh-6);\n  });\n  ctx.textAlign='left';\n  // grid lines\n  for(let i=0;i<=4;i++){\n    const gy=y0+h-i*(h/4);\n    ctx.strokeStyle='rgba(255,255,255,0.06)';\n    ctx.beginPath(); ctx.moveTo(x0,gy); ctx.lineTo(x0+w,gy); ctx.stroke();\n  }\n}\n\nfunction drawLine(){\n  const x0=440, y0=30, w=340, h=180;\n  ctx.fillStyle='#fff'; ctx.font='bold 13px monospace';\n  ctx.fillText('Latency (ms)',x0,y0-8);\n  const step=w/(line.length-1);\n  ctx.beginPath();\n  ctx.moveTo(x0,y0+h-line[0]/100*h);\n  line.forEach((v,i)=>{\n    ctx.lineTo(x0+i*step,y0+h-v/100*h);\n  });\n  ctx.strokeStyle='#06b6d4'; ctx.lineWidth=2; ctx.stroke();\n  // fill under\n  ctx.lineTo(x0+(line.length-1)*step,y0+h);\n  ctx.lineTo(x0,y0+h);\n  ctx.closePath();\n  ctx.fillStyle='rgba(6,182,212,0.08)'; ctx.fill();\n  ctx.lineWidth=1;\n  // grid\n  for(let i=0;i<=4;i++){\n    const gy=y0+h-i*(h/4);\n    ctx.strokeStyle='rgba(255,255,255,0.06)';\n    ctx.beginPath(); ctx.moveTo(x0,gy); ctx.lineTo(x0+w,gy); ctx.stroke();\n  }\n}\n\nfunction drawDonut(){\n  const cx=200, cy=360, r=80, rInner=50;\n  ctx.fillStyle='#fff'; ctx.font='bold 13px monospace';\n  ctx.fillText('Service Distribution',40,260);\n  const total=cats.reduce((a,b)=>a+b,0);\n  let angle=-Math.PI/2;\n  cats.forEach((v,i)=>{\n    const slice=v/total*Math.PI*2;\n    ctx.beginPath();\n    ctx.arc(cx,cy,r,angle,angle+slice);\n    ctx.arc(cx,cy,rInner,angle+slice,angle,true);\n    ctx.closePath();\n    ctx.fillStyle=colors[i]; ctx.fill();\n    // label\n    const mid=angle+slice/2;\n    const lx=cx+Math.cos(mid)*(r+20);\n    const ly=cy+Math.sin(mid)*(r+20);\n    ctx.fillStyle='#ccc'; ctx.font='10px monospace'; ctx.textAlign='center';\n    ctx.fillText(catLabels[i]+' '+Math.round(v/total*100)+'%',lx,ly);\n    angle+=slice;\n  });\n  ctx.textAlign='left';\n  // center text\n  ctx.fillStyle='#fff'; ctx.font='bold 16px monospace'; ctx.textAlign='center';\n  ctx.fillText(Math.round(total),cx,cy+6);\n  ctx.textAlign='left';\n}\n\nfunction drawStats(){\n  const x0=440, y0=260;\n  ctx.fillStyle='#fff'; ctx.font='bold 13px monospace';\n  ctx.fillText('Live Metrics',x0,y0);\n  const metrics=[\n    {label:'Uptime',val:'99.97%',color:'#10b981'},\n    {label:'Errors/min',val:Math.round(Math.random()*5).toString(),color:'#f43f5e'},\n    {label:'Avg Response',val:Math.round(line[line.length-1])+'ms',color:'#06b6d4'},\n    {label:'Active Users',val:Math.round(300+Math.random()*50).toString(),color:'#a855f7'},\n  ];\n  metrics.forEach((m,i)=>{\n    const my=y0+25+i*42;\n    ctx.fillStyle='rgba(255,255,255,0.05)';\n    ctx.fillRect(x0,my,340,34);\n    ctx.fillStyle='#888'; ctx.font='11px monospace';\n    ctx.fillText(m.label,x0+12,my+22);\n    ctx.fillStyle=m.color; ctx.font='bold 14px monospace';\n    ctx.textAlign='right';\n    ctx.fillText(m.val,x0+328,my+22);\n    ctx.textAlign='left';\n  });\n}\n\nfunction drawFPS(ts){\n  if(ts-lastTime>=1000){ fps=frame; frame=0; lastTime=ts; }\n  frame++;\n  ctx.fillStyle='#444'; ctx.font='10px monospace';\n  ctx.fillText(fps+' fps',W-50,H-8);\n}\n\nfunction update(){\n  if(Math.random()<0.03) bars.forEach(b=>b.target=Math.random()*100);\n  line.push(Math.max(10,Math.min(90,line[line.length-1]+(Math.random()-0.5)*12)));\n  if(line.length>40) line.shift();\n  cats=cats.map(v=>Math.max(5,v+(Math.random()-0.5)*3));\n}\n\nfunction render(ts){\n  ctx.fillStyle='#0a0a1a'; ctx.fillRect(0,0,W,H);\n  update();\n  drawBars();\n  drawLine();\n  drawDonut();\n  drawStats();\n  drawFPS(ts);\n  requestAnimationFrame(render);\n}\nrequestAnimationFrame(render);\n</script>\n</body>\n</html>","README.md":"# Canvas Data Dashboard\n\nAn animated real-time data dashboard built with HTML5 Canvas.\n\n## Features\n- Animated bar chart with smooth lerp transitions\n- Scrolling line chart with gradient fill\n- Donut chart with percentage labels\n- Live metrics panel with random data simulation\n- 60fps rendering with FPS counter\n- Dark theme with neon accent colors\n\n## Run\nOpen `dashboard.html` in any modern browser. No dependencies required.\n"}}