{"claude_md":"# Canvas Particle System\n\nHTML5 Canvas particle fountain with gravity, color palettes, and fade trails. Beginner-friendly visual demo.\n\n## Quick Reference\n\n# Canvas Particle System\n\n> **Difficulty:** Beginner | **Runtime:** HTML5 Canvas | **Output:** Visual animation\n\nTeach an AI agent to generate a colorful particle fountain with gravity, fade trails, and configurable color palettes using the HTML5 Canvas API.\n\n## What You'll Build\n\nA self-contained HTML file that renders an animated particle system:\n- Particles spray upward from the bottom center of the canvas\n- Gravity pulls particles back down in natural arcs\n- Each particle has a random color from a curated palette\n- Particles fade out as they age, creating trailing effects\n- The system runs at 60fps using `requestAnimationFrame`\n\n## Core Concepts\n\n### 1. Particle Data Structure\n\nEach particle tracks position, velocity, age, and color:\n\n```javascript\n{\n  x: number,       // horizontal position\n  y: number,       // vertical position\n  vx: number,      // horizontal velocity\n  vy: number,      // vertical velocity\n  life: number,    // remaining life (0-1)\n  color: string,   // HSL color string\n  size: number     // radius in pixels\n}\n```\n\n### 2. Physics Update Loop\n\nEvery frame:\n1. **Emit** new particles at the source point\n2. **Update** each particle's position: `x += vx`, `y += vy`\n3. **Apply gravity**: `vy += GRAVITY`\n4. **Age** particles: `life -= decay`\n5. **Remove** dead particles (`life <= 0`)\n6. **Render** each particle as a filled circle with alpha = life\n\n### 3. Color Palettes\n\nUse HSL color space for vibrant, varied particles:\n- **Fire:** hues 0-60 (red → yellow)\n- **Ocean:** hues 180-240 (cyan → blue)\n- **Forest:** hues 90-150 (green spectrum)\n- **Rainbow:** random hue 0-360\n\n## Instructions\n\n1. Create an HTML file with a full-viewport `<canvas>`\n2. Set up the animation loop with `requestAnimationFrame`\n3. Implement the particle emitter at bottom-center\n4. Add gravity and fade effects\n5. Use semi-transparent background fills for trail effects\n\n## Parameters\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `PARTICLE_COUNT` | 5 | Particles emitted per frame |\n| `GRAVITY` | 0.15 | Downward acceleration |\n| `SPEED` | 4 | Initial velocity magnitude |\n| `DECAY` | 0.012 | Life reduction per frame |\n| `TRAIL_ALPHA` | 0.08 | Background clear opacity (lower = longer trails) |\n\n## Agent Docs (read when relevant)\n\n| File | When to read |\n|------|-------------|\n| `agent_docs/particles.html` | particles |\n| `agent_docs/README.md` | README |\n","agent_docs":{"agent_docs/particles.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>Canvas Particle System</title>\n<style>\n  * { margin: 0; padding: 0; box-sizing: border-box; }\n  body { background: #0a0a0a; overflow: hidden; }\n  canvas { display: block; }\n</style>\n</head>\n<body>\n<canvas id=\"c\"></canvas>\n<script>\nconst canvas = document.getElementById('c');\nconst ctx = canvas.getContext('2d');\ncanvas.width = window.innerWidth;\ncanvas.height = window.innerHeight;\n\nconst PARTICLE_COUNT = 5;\nconst GRAVITY = 0.15;\nconst SPEED = 4;\nconst DECAY = 0.012;\nconst TRAIL_ALPHA = 0.08;\n\nconst palettes = [\n  () => `hsl(${Math.random() * 60}, 100%, ${50 + Math.random() * 30}%)`,\n  () => `hsl(${180 + Math.random() * 60}, 80%, ${40 + Math.random() * 30}%)`,\n  () => `hsl(${90 + Math.random() * 60}, 70%, ${35 + Math.random() * 30}%)`,\n  () => `hsl(${Math.random() * 360}, 90%, ${50 + Math.random() * 20}%)`,\n];\nlet currentPalette = palettes[3];\nlet particles = [];\n\nfunction emit() {\n  for (let i = 0; i < PARTICLE_COUNT; i++) {\n    const angle = -Math.PI / 2 + (Math.random() - 0.5) * 1.2;\n    const speed = SPEED * (0.5 + Math.random());\n    particles.push({\n      x: canvas.width / 2,\n      y: canvas.height - 20,\n      vx: Math.cos(angle) * speed,\n      vy: Math.sin(angle) * speed,\n      life: 1,\n      color: currentPalette(),\n      size: 2 + Math.random() * 3,\n    });\n  }\n}\n\nfunction update() {\n  for (let i = particles.length - 1; i >= 0; i--) {\n    const p = particles[i];\n    p.x += p.vx;\n    p.y += p.vy;\n    p.vy += GRAVITY;\n    p.life -= DECAY;\n    if (p.life <= 0) particles.splice(i, 1);\n  }\n}\n\nfunction draw() {\n  ctx.fillStyle = `rgba(10, 10, 10, ${TRAIL_ALPHA})`;\n  ctx.fillRect(0, 0, canvas.width, canvas.height);\n  for (const p of particles) {\n    ctx.globalAlpha = p.life;\n    ctx.fillStyle = p.color;\n    ctx.beginPath();\n    ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);\n    ctx.fill();\n  }\n  ctx.globalAlpha = 1;\n}\n\nfunction loop() {\n  emit();\n  update();\n  draw();\n  requestAnimationFrame(loop);\n}\n\n// Cycle palettes on click\ncanvas.addEventListener('click', () => {\n  const idx = (palettes.indexOf(currentPalette) + 1) % palettes.length;\n  currentPalette = palettes[idx];\n});\n\nwindow.addEventListener('resize', () => {\n  canvas.width = window.innerWidth;\n  canvas.height = window.innerHeight;\n});\n\nloop();\n</script>\n</body>\n</html>","agent_docs/README.md":"# Canvas Particle System\n\nA beginner-friendly HTML5 Canvas particle fountain demo.\n\n## Running\n\nOpen `particles.html` in any modern browser. Click to cycle through color palettes.\n\n## Customization\n\nEdit the constants at the top of the script:\n- `PARTICLE_COUNT` — particles per frame (higher = denser)\n- `GRAVITY` — downward pull strength\n- `SPEED` — initial burst velocity\n- `DECAY` — how fast particles fade\n- `TRAIL_ALPHA` — trail length (lower = longer)"}}