oneshotlm
Compare all models on this prompt →

Bouncing balls in a heptagon · deepseek-chat

Show 20 numbered balls (1 to 20) dropping from the center of a heptagon that spins 360 degrees every 5 seconds. The balls are affected by gravity and friction, collide with each other, and bounce realistically off the rotating walls; show each ball's spin via the rotation of its number. Implement all collision detection yourself.

⚠ no runnable output

This one-shot run produced no runnable artifact.

agent produced no index.html

The transcript below shows what the model did — read it to see why the one shot fell short.

transcript · 2 messages
user

Show 20 numbered balls (1 to 20) dropping from the center of a heptagon that spins 360 degrees every 5 seconds. The balls are affected by gravity and friction, collide with each other, and bounce realistically off the rotating walls; show each ball's spin via the rotation of its number. Implement all collision detection yourself.

assistant

Here’s the complete `index.html` file with a spinning heptagon and 20 numbered balls that bounce realistically, including collision detection and ball rotation: html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Spinning Heptagon with Balls</title> <style> body { margin: 0; overflow: hidden; background: #111; } canvas { display: block; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Constants const GRAVITY = 0.2; const FRICTION = 0.99; const RESTITUTION = 0.8; const BALL_RADIUS = 15; const HEPTAGON_RADIUS = Math.min(canvas.width, canvas.height) * 0.4; const HEPTAGON_SIDES = 7; const CENTER = { x: canvas.width / 2, y: canvas.height / 2 }; const BALL_COLORS = [ '#FF5733', '#33FF57', '#3357FF', '#FF33F5', '#33FFF5', '#F5FF33', '#A633FF', '#FFA633', '#33FFA6', '#FF33A6', '#33A6FF', '#A6FF33', '#FF3366', '#66FF33', '#3366FF', '#FF6633', '#33FF66', '#6633FF', '#FF33CC', '#33CCFF' ]; // Heptagon properties let heptagonAngle = 0; const heptagonRotationSpeed = (2 * Math.PI) / (5 * 60); // 360 degrees every 5 seconds // Generate heptagon vertices function getHeptagonVertices() { const vertices = []; for (let i = 0; i < HEPTAGON_SIDES; i++) { const angle = heptagonAngle + (i * 2 * Math.PI / HEPTAGON_SIDES); vertices.push({ x: CENTER.x + HEPTAGON_RADIUS * Math.cos(angle), y: CENTER.y + HEPTAGON_RADIUS * Math.sin(angle) }); } return vertices; } // Ball class class Ball { constructor(number) { this.number = number; this.x = CENTER.x; this.y = CENTER.y; this.vx = (Math.random() * 4 - 2); this.vy = (Math.random() * 4 - 2); this.radius = BALL_RADIUS; this.color = BALL_COLORS[number % BALL_COLORS.length]; this.rotation = 0; this.rotationSpeed = (Math.random() * 0.1 - 0.05); } update() { // Apply gravity this.vy += GRAVITY; // Apply friction this.vx *= FRICTION; this.vy *= FRICTION; // Update position this.x += this.vx; this.y += this.vy; // Update rotation this.rotation += this.rotationSpeed; // Bounce off walls (heptagon) const vertices = getHeptagonVertices(); for (let i = 0; i < vertices.length; i++) { const p1 = vertices[i]; const p2 = vertices[(i + 1) % vertices.length]; this.checkCollisionWithWall(p1, p2); } // Bounce off other balls for (let other of balls) { if (other !== this) { this.checkCollisionWithBall(other); } } } checkCollisionWithWall(p1, p2) { // Line segment collision detection const ballToLine = { x: this.x - p1.x, y: this.y - p1.y }; const lineDir = { x: p2.x - p1.x, y: p2.y - p1.y }; const lineLength = Math.hypot(lineDir.x, lineDir.y); const unitLineDir = { x: lineDir.x / lineLength, y: lineDir.y / lineLength }; // Project ball position onto line const projLength = ballToLine.x * unitLineDir.x + ballToLine.y * unitLineDir.y; // Closest point on line to ball let closestPoint; if (projLength < 0) { closestPoint = p1; } else if (projLength > lineLength) { closestPoint = p2; } else { closestPoint = { x: p1.x + projLength * unitLineDir.x, y: p1.y + projLength * unitLineDir.y }; } // Distance to closest point const distance = Math.hypot(this.x - closestPoint.x, this.y - closestPoint.y); if (distance < this.radius) { // Collision detected const normal = { x: this.x - closestPoint.x, y: this.y - closestPoint.y }; const norm = Math.hypot(normal.x, normal.y); normal.x /= norm; normal.y /= norm; // Reflect velocity const dotProduct = this.vx * normal.x + this.vy * normal.y; this.vx -= 2 * dotProduct * normal.x * RESTITUTION; this.vy -= 2 * dotProduct * normal.y * RESTITUTION; // Move ball out of collision const overlap = this.radius - distance; this.x += overlap * normal.x; this.y += overlap * normal.y; } } checkCollisionWithBall(other) { const dx = other.x - this.x; const dy = other.y - this.y; const distance = Math.hypot(dx, dy); const minDistance = this.radius + other.radius; if (distance < minDistance) { // Collision detected const nx = dx / distance; const ny = dy / distance; const p = 2 * (this.vx * nx + this.vy * ny - other.vx * nx - other.vy * ny) / (this.radius + other.radius); // Update velocities for elastic collision this.vx -= p * other.radius * nx * RESTITUTION; this.vy -= p * other.radius * ny * RESTITUTION; other.vx += p * this.radius * nx * RESTITUTION; other.vy += p * this.radius * ny * RESTITUTION; // Move balls apart to avoid overlap const overlap = (minDistance - distance) / 2; this.x -= overlap * nx; this.y -= overlap * ny; other.x += overlap * nx; other.y += overlap * ny; } } draw() { ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.rotation); // Draw ball ctx.beginPath(); ctx.arc(0, 0, this.radius, 0, Math.PI * 2); ctx.fillStyle = this.color; ctx.fill(); ctx.strokeStyle = '#fff'; ctx.stroke(); // Draw number ctx.fillStyle = '#fff'; ctx.font = `${BALL_RADIUS}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(this.number.toString(), 0, 0); ctx.restore(); } } // Create balls const balls = []; for (let i = 1; i <= 20; i++) { balls.push(new Ball(i)); } // Animation loop function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Update heptagon rotation heptagonAngle += heptagonRotationSpeed; if (heptagonAngle > 2 * Math.PI) heptagonAngle -= 2 * Math.PI; // Draw heptagon const vertices = getHeptagonVertices(); ctx.beginPath(); ctx.moveTo(vertices[0].x, vertices[0].y); for (let i = 1; i < vertices.length; i++) { ctx.lineTo(vertices[i].x, vertices[i].y); } ctx.closePath(); ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.stroke(); // Update and draw balls for (let ball of balls) { ball.update(); ball.draw(); } requestAnimationFrame(animate); } animate(); // Resize handler window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; CENTER.x = canvas.width / 2; CENTER.y = canvas.height / 2; }); </script> </body> </html> This file includes: 1. A spinning heptagon with 7 sides. 2. 20 numbered balls with unique colors, each with its own rotation. 3. Realistic physics for gravity, friction, and collisions (between balls and the heptagon walls). 4. Dynamic resizing for the canvas.

TAKE IT TO CODE

This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.

RUN

modeldeepseek-chat
vendorDeepSeek
harnesspi-agent
generated2026-08-01

METRICS

runtime24.8s
tokens in1.6k
tokens out2.1k
cached0
cost / run$0.0020