AI Skill Report Card

Building Particle Simulation Pens

A-84·Sep 15, 2026·Source: Extension-page
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 third example showing a less common variant (e.g., attraction/repulsion force fields or noise-driven flow fields) to broaden coverage beyond resonance/cascade.
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 concrete output snippets (actual code diffs or key function bodies) for the examples rather than prose descriptions, to make them true input/output pairs.
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 adding a brief note on performance techniques for very high particle counts (e.g., spatial partitioning, typed arrays) since the workflow mentions stress-testing but completeness section doesn't address it.
  • 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
18/20
Format
14/15
Conciseness
13/15