AI Skill Report Card

Building Particle Simulation Pens

A-83·Sep 15, 2026·Source: Web
15 / 15

Produce a single self-contained HTML document with inline <style> and <script>, using <canvas> for rendering and a floating .controls panel with <input type="range"> sliders bound to simulation parameters via oninput or addEventListener.

HTML
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Particle Resonance Simulation</title> <style> body,html{margin:0;padding:0;overflow:hidden;background:#000;} canvas{display:block;} .controls{position:fixed;top:10px;left:10px;color:#fff;font-family:monospace; background:rgba(0,0,0,0.5);padding:10px;border-radius:5px;} .controls label{display:block;margin-bottom:5px;} .controls input{width:200px;} </style> </head> <body> <canvas id="c"></canvas> <div class="controls"> <label>Particles: <span id="countVal">200</span> <input type="range" id="count" min="10" max="2000" value="200"></label> <label>Speed: <span id="speedVal">1</span> <input type="range" id="speed" min="0" max="5" step="0.1" value="1"></label> </div> <script> const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); let W, H; function resize(){ W = canvas.width = innerWidth; H = canvas.height = innerHeight; } addEventListener('resize', resize); resize(); const params = { count: 200, speed: 1 }; function bindSlider(id, key, decimals=0){ const el = document.getElementById(id); const out = document.getElementById(id+'Val'); el.addEventListener('input', () => { params[key] = parseFloat(el.value); out.textContent = params[key].toFixed(decimals); }); } bindSlider('count','count'); bindSlider('speed','speed',1); let particles = []; function initParticles(){ particles = Array.from({length: params.count}, () => ({ x: Math.random()*W, y: Math.random()*H, vx: (Math.random()-0.5)*params.speed, vy: (Math.random()-0.5)*params.speed, hue: Math.random()*360 })); } initParticles(); function step(){ ctx.fillStyle = 'rgba(0,0,0,0.15)'; ctx.fillRect(0,0,W,H); for(const p of particles){ p.x += p.vx; p.y += p.vy; if(p.x<0||p.x>W) p.vx*=-1; if(p.y<0||p.y>H) p.vy*=-1; ctx.beginPath(); ctx.arc(p.x,p.y,2,0,Math.PI*2); ctx.fillStyle = `hsl(${p.hue},80%,60%)`; ctx.fill(); } requestAnimationFrame(step); } step(); </script> </body> </html>
Recommendation
Add a second full example showing actual code diffs or output snippet, not just prose description, to strengthen concrete input/output pairing
14 / 15

Progress:

  • Step 1: Define the simulation concept (particle field, force type: attraction/repulsion/resonance/cascade, entropy/noise source)
  • Step 2: Set up canvas, full-viewport sizing, resize handling, dark background
  • Step 3: Build particle data model (position, velocity, mass, phase, color) as array of objects
  • Step 4: Implement physics/update step (forces, collisions, decay, boundary behavior)
  • Step 5: Implement render step (trail fade via low-alpha fillRect, glow via shadowBlur or additive blending)
  • Step 6: Add .controls panel with range inputs for key parameters (count, speed, force strength, entropy, decay)
  • Step 7: Bind inputs to live-update params object; display current value next to each slider
  • Step 8: Wire requestAnimationFrame loop; ensure it references live params object, not stale copies
  • Step 9: Test at extremes (min/max slider values, 0 particles, resize mid-animation)
  • Step 10: Polish visuals (color palette, blend modes, trail persistence) and performance (cap particle count reasonably, use for loops over forEach for large N)
Recommendation
Include a 'bad output' example (e.g., stale closure slider bug, or clearRect misuse) to contrast good vs poor implementations
14 / 20

Example 1: Input: "Build an entropic cascade simulation where particles lose energy over time and trigger cascading color shifts on collision." Output: Canvas sim with particle objects holding energy (decays each frame via energy *= 0.995), collision detection via distance check, on collision spawn 2-3 child particles with inherited hue+random offset (cascade effect), controls for initial energy, decay rate, and cascade branching factor.

Example 2: Input: "Particle resonance simulation with adjustable frequency." Output: Particles oscillate position via sin(time * frequency + phase), frequency slider modulates a shared or per-particle value, visual resonance shown via synchronized pulsing size/opacity when phases align.

Recommendation
Consider showing a force-based (attraction/repulsion) example since it's mentioned in workflow step 1 but never demonstrated
  • Keep everything in one file unless explicitly asked to split HTML/CSS/JS.
  • Use requestAnimationFrame, never setInterval, for animation loops.
  • Fade trails with ctx.fillStyle = 'rgba(0,0,0,alpha)' + fillRect instead of clearRect for motion-blur aesthetics.
  • Store all tunable values in one params object; sliders mutate it, render/update loop reads it — avoids stale closures.
  • Display live numeric value next to each slider (<span> updated on input event).
  • Default canvas to full viewport, overflow:hidden on body/html, dark background for contrast with glowing particles.
  • Use hsl() color for easy hue-cycling effects.
  • Cap default particle counts (~200-500) for smooth performance; let slider allow higher for stress-testing.
  • Handle window resize without resetting particle state abruptly (rescale positions if needed).
  • Don't use clearRect every frame if trail effects are desired — it erases history instantly.
  • Don't bind sliders with one-time value reads instead of live event listeners — controls won't do anything.
  • Don't forget canvas sizing on load AND resize — a 300x150 default canvas silently breaks full-screen sims.
  • Don't let particle arrays grow unbounded in cascade/spawn effects — cap max count or cull dead/low-energy particles.
  • Don't mix requestAnimationFrame timing with fixed-step physics assumptions — use delta time if frame-rate independence matters.
  • Don't hardcode colors/sizes when a slider-driven parameter would make the demo more compelling and inspectable.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
15/15
Workflow
14/15
Examples
14/20
Completeness
17/20
Format
15/15
Conciseness
13/15