Boids flocking · qwen3-30b-a3b
Create a full-screen flocking simulation of boids using separation, alignment, and cohesion, drawn as oriented triangles that steer smoothly and flee from the mouse cursor.
transcript · 4 messages
Create a full-screen flocking simulation of boids using separation, alignment, and cohesion, drawn as oriented triangles that steer smoothly and flee from the mouse cursor.
thinking
Okay, the user wants a full-screen flocking simulation of boids with separation, alignment, cohesion, and they should flee from the mouse cursor. All in a single HTML file with inline CSS and JS, no external resources. First, I need to recall how boids work. Boids have three main behaviors: separation (avoid crowding), alignment (match velocity), and cohesion (move towards center). Plus, they should flee from the mouse. I'll start by setting up the HTML structure. A canvas element that takes the full screen. Then, the CSS will make the body and canvas full screen, removing margins and padding. For JavaScript, I'll need to create a Boid class. Each boid will have position, velocity, and acceleration. The update method will handle the three rules and mouse evasion. Separation: Check nearby boids and steer away. Alignment: Average the velocities of nearby boids. Cohesion: Steer towards the average position of nearby boids. Flee: If the mouse is close, steer away. I'll need functions to calculate the distance between boids and the mouse. Also, limit the acceleration to keep things smooth. The canvas will be cleared each frame, and each boid will be drawn as a triangle. The mouse movement event will update the mouse position. Testing the code in a single file. Make sure all the code is self-contained. No external libraries, just plain JS and HTML. Wait, the user said no external resources, so all code must be inline. The canvas element is straightforward. The JS will handle the simulation loop with requestAnimationFrame. Potential issues: Performance with many boids. But since it's a simple simulation, it should work. Also, ensuring the triangle is oriented correctly based on the boid's velocity. I'll write the code step by step, making sure each part is included. Then, check for any syntax errors. Finally, output the index.html with all the code inside.
index.html (5373 bytes)Successfully wrote 5373 bytes to index.html
thinking
Okay, I need to create a full-screen flocking simulation of boids with separation, alignment, cohesion, and fleeing from the mouse. The user wants everything in a single HTML file with inline CSS and JS, no external resources. First, I'll start by setting up the basic HTML structure. The canvas element will take the full screen, so I'll use CSS to make the body and canvas fill the window. Then, I'll add a script tag for the JavaScript. For the JavaScript, I'll define a Boid class. Each boid needs position, velocity, and acceleration. The update method will handle the three rules: separation, alignment, cohesion, and fleeing from the mouse. Separation involves steering away from nearby boids. Alignment makes boids match their neighbors' velocity. Cohesion steers them towards the average position of neighbors. Fleeing from the mouse requires checking the distance and steering away if the mouse is too close. I'll need helper functions to calculate distances and manage the boid behaviors. The draw method will render each boid as a triangle, oriented in the direction of their velocity. The canvas will be resized to fit the window, and the animation loop will use requestAnimationFrame for smooth updates. The mouse position is tracked via the mousemove event. I'll make sure all code is self-contained, with no external libraries. Testing the code in a browser should display the simulation. I'll check for any syntax errors and ensure the canvas is properly cleared each frame with a semi-transparent fill to create a trailing effect.
Here's a full-screen boids simulation with separation, alignment, cohesion, and mouse evasion, all in a single HTML file: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Boids Simulation</title> <style> html, body { margin: 0; padding: 0; overflow: hidden; height: 100%; width: 100%; background: #000; } canvas { display: block; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let width, height; function resize() { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; } window.addEventListener('resize', resize); resize(); const NUM_BOIDS = 200; const MAX_SPEED = 3; const MAX_FORCE = 0.05; const SEPARATION_RADIUS = 25; const ALIGNMENT_RADIUS = 50; const COHESION_RADIUS = 75; const FLEE_RADIUS = 50; class Boid { constructor() { this.pos = { x: Math.random() * width, y: Math.random() * height }; this.vel = { x: (Math.random() - 0.5) * 2, y: (Math.random() - 0.5) * 2 }; this.acc = { x: 0, y: 0 }; } update(boids, mouse) { this.acc = { x: 0, y: 0 }; this.separate(boids); this.align(boids); this.cohere(boids); this.flee(mouse); this.vel.x += this.acc.x; this.vel.y += this.acc.y; // Limit speed const speed = Math.sqrt(this.vel.x**2 + this.vel.y**2); if (speed > MAX_SPEED) { this.vel.x = (this.vel.x / speed) * MAX_SPEED; this.vel.y = (this.vel.y / speed) * MAX_SPEED; } this.pos.x += this.vel.x; this.pos.y += this.vel.y; // Wrap around screen if (this.pos.x < 0) this.pos.x = width; if (this.pos.x > width) this.pos.x = 0; if (this.pos.y < 0) this.pos.y = height; if (this.pos.y > height) this.pos.y = 0; } separate(boids) { let total = 0; let avg = { x: 0, y: 0 }; for (const other of boids) { if (other === this) continue; const d = this.distance(this.pos, other.pos); if (d < SEPARATION_RADIUS && d > 0) { const diff = { x: this.pos.x - other.pos.x, y: this.pos.y - other.pos.y }; diff.x /= d; diff.y /= d; avg.x += diff.x; avg.y += diff.y; total++; } } if (total > 0) { avg.x /= total; avg.y /= total; avg.x = (avg.x / Math.abs(avg.x)) * MAX_SPEED; avg.y = (avg.y / Math.abs(avg.y)) * MAX_SPEED; this.acc.x += (avg.x - this.vel.x) * 0.05; this.acc.y += (avg.y - this.vel.y) * 0.05; } } align(boids) { let total = 0; let avg = { x: 0, y: 0 }; for (const other of boids) { if (other === this) continue; const d = this.distance(this.pos, other.pos); if (d < ALIGNMENT_RADIUS) { avg.x += other.vel.x; avg.y += other.vel.y; total++; } } if (total > 0) { avg.x /= total; avg.y /= total; avg.x = (avg.x / Math.abs(avg.x)) * MAX_SPEED; avg.y = (avg.y / Math.abs(avg.y)) * MAX_SPEED; this.acc.x += (avg.x - this.vel.x) * 0.05; this.acc.y += (avg.y - this.vel.y) * 0.05; } } cohere(boids) { let total = 0; let avg = { x: 0, y: 0 }; for (const other of boids) { if (other === this) continue; const d = this.distance(this.pos, other.pos); if (d < COHESION_RADIUS) { avg.x += other.pos.x; avg.y += other.pos.y; total++; } } if (total > 0) { avg.x /= total; avg.y /= total; const desired = { x: avg.x - this.pos.x, y: avg.y - this.pos.y }; const desiredLen = Math.sqrt(desired.x**2 + desired.y**2); if (desiredLen > 0) { desired.x /= desiredLen; desired.y /= desiredLen; desired.x *= MAX_SPEED; desired.y *= MAX_SPEED; const steer = { x: desired.x - this.vel.x, y: desired.y - this.vel.y }; this.acc.x += steer.x * 0.05; this.acc.y += steer.y * 0.05; } } } flee(mouse) { const d = this.distance(this.pos, mouse); if (d < FLEE_RADIUS) { const desired = { x: (this.pos.x - mouse.x) / d * MAX_SPEED, y: (this.pos.y - mouse.y) / d * MAX_SPEED }; const steer = { x: desired.x - this.vel.x, y: desired.y - this.vel.y }; this.acc.x += steer.x * 0.1; this.acc.y += steer.y * 0.1; } } distance(a, b) { return Math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2); } draw() { ctx.save(); ctx.translate(this.pos.x, this.pos.y); ctx.rotate(Math.atan2(this.vel.y, this.vel.x)); ctx.beginPath(); ctx.moveTo(0, -5); ctx.lineTo(-5, 5); ctx.lineTo(5, 5); ctx.closePath(); ctx.fillStyle = '#0f0'; ctx.fill(); ctx.restore(); } } const boids = Array.from({ length: NUM_BOIDS }, () => new Boid()); let mouse = { x: width/2, y: height/2 }; window.addEventListener('mousemove', (e) => { mouse.x = e.clientX; mouse.y = e.clientY; }); function animate() { ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; ctx.fillRect(0, 0, width, height); for (const boid of boids) { boid.update(boids, mouse); boid.draw(); } requestAnimationFrame(animate); } animate(); </script> </body> </html> ``` This code creates a full-screen boids simulation with the following features: 1. **Separation**: Boids steer to avoid crowding each other 2. **Alignment**: Boids align their direction with nearby boids 3. **Cohesion**: Boids steer towards the center of mass of nearby boids 4. **Fleeing**: Boids flee from the mouse cursor when it gets too close 5. **Smooth movement**: Boids move smoothly with velocity and acceleration 6. **Screen wrapping**: Boids wrap around the edges of the screen 7. **Visual representation**: Boids are drawn as oriented triangles The simulation runs in a single HTML file with all CSS and JavaScript embedded directly in the document.
TAKE IT TO CODE
A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.
RUN
EVALUATION
Boids flock in green triangular clusters, animating smoothly with continuous motion, though mouse flee/click reaction unclear.
Vision grade · anthropic/claude-sonnet-5
MEASUREMENTS
Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.