Ten Balls in a Spinning Hexagon — JS Animation

animation 13 个模型 2026-10-18

共同提示词

user prompt
Create an animation in JS with 10 balls bouncing inside a spinning hexagon.

来源: Artificial Analysis MicroEval (public model outputs)

源站为渲染额外加入了未公开的 system prompt;此处只展示可见的 user prompt。

模型结果

DeepSeek

DeepSeek R1 0528 (May '25)

最终回答
# Bouncing Balls in a Spinning Hexagon

I'll create an animation with 10 balls bouncing inside a rotating hexagon using pure JavaScript and Canvas API.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #1a1a2e, #16213e);
            overflow: hidden;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        .container {
            position: relative;
            width: 800px;
            max-width: 95%;
            text-align: center;
        }
        
        canvas {
            background: rgba(0, 0, 0, 0.2);
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
        }
        
        h1 {
            color: #fff;
            text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
            margin-bottom: 20px;
            font-weight: 600;
            letter-spacing: 1px;
        }
        
        .controls {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 20px;
            flex-wrap: wrap;
        }
        
        button {
            background: #4cc9f0;
            color: #1a1a2e;
            border: none;
            padding: 10px 20px;
            border-radius: 50px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }
        
        button:hover {
            background: #4361ee;
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
        }
        
        button:active {
            transform: translateY(1px);
        }
        
        .info {
            color: rgba(255, 255, 255, 0.7);
            margin-top: 15px;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Bouncing Balls in a Spinning Hexagon</h1>
        <canvas id="canvas" width="700" height="500"></canvas>
        <div class="controls">
            <button id="speedUp">Speed Up</button>
            <button id="slowDown">Slow Down</button>
            <button id="reset">Reset</button>
        </div>
        <div class="info">Click anywhere to add more balls (max 20)</div>
    </div>

    <script>
        // Canvas setup
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        
        // Hexagon properties
        const hexRadius = 180;
        let hexRotation = 0;
        let rotationSpeed = 0.005;
        
        // Ball properties
        const balls = [];
        const maxBalls = 20;
        const colors = [
            '#FF5252', '#FF4081', '#E040FB', '#7C4DFF', 
            '#536DFE', '#448AFF', '#40C4FF', '#18FFFF', 
            '#64FFDA', '#69F0AE', '#B2FF59', '#EEFF41'
        ];
        
        // Initialize balls
        function initBalls(count) {
            for (let i = 0; i < count; i++) {
                createBall();
            }
        }
        
        // Create a new ball
        function createBall() {
            if (balls.length >= maxBalls) return;
            
            const radius = 10 + Math.random() * 10;
            const angle = Math.random() * Math.PI * 2;
            const distance = Math.random() * (hexRadius - radius - 20);
            
            const ball = {
                x: centerX + Math.cos(angle) * distance,
                y: centerY + Math.sin(angle) * distance,
                radius: radius,
                vx: (Math.random() - 0.5) * 4,
                vy: (Math.random() - 0.5) * 4,
                color: colors[Math.floor(Math.random() * colors.length)]
            };
            
            balls.push(ball);
        }
        
        // Get hexagon vertices
        function getHexagonVertices() {
            const vertices = [];
            for (let i = 0; i < 6; i++) {
                const angle = hexRotation + i * Math.PI / 3;
                vertices.push({
                    x: centerX + hexRadius * Math.cos(angle),
                    y: centerY + hexRadius * Math.sin(angle)
                });
            }
            return vertices;
        }
        
        // Get hexagon edges
        function getHexagonEdges(vertices) {
            const edges = [];
            for (let i = 0; i < 6; i++) {
                edges.push({
                    start: vertices[i],
                    end: vertices[(i + 1) % 6]
                });
            }
            return edges;
        }
        
        // Calculate distance from point to line segment
        function distanceToSegment(point, edge) {
            const A = point.x - edge.start.x;
            const B = point.y - edge.start.y;
            const C = edge.end.x - edge.start.x;
            const D = edge.end.y - edge.start.y;
            
            const dot = A * C + B * D;
            const lenSq = C * C + D * D;
            let param = -1;
            
            if (lenSq !== 0) {
                param = dot / lenSq;
            }
            
            let xx, yy;
            
            if (param < 0) {
                xx = edge.start.x;
                yy = edge.start.y;
            } else if (param > 1) {
                xx = edge.end.x;
                yy = edge.end.y;
            } else {
                xx = edge.start.x + param * C;
                yy = edge.start.y + param * D;
            }
            
            const dx = point.x - xx;
            const dy = point.y - yy;
            return Math.sqrt(dx * dx + dy * dy);
        }
        
        // Calculate normal vector for an edge
        function getEdgeNormal(edge) {
            const dx = edge.end.x - edge.start.x;
            const dy = edge.end.y - edge.start.y;
            const length = Math.sqrt(dx * dx + dy * dy);
            
            // Normal vector (perpendicular to the edge)
            return {
                x: -dy / length,
                y: dx / length
            };
        }
        
        // Update ball positions and handle collisions
        function updateBalls(edges) {
            for (const ball of balls) {
                // Update position
                ball.x += ball.vx;
                ball.y += ball.vy;
                
                // Check collision with hexagon edges
                for (const edge of edges) {
                    const distance = distanceToSegment(ball, edge);
                    
                    if (distance < ball.radius) {
                        const normal = getEdgeNormal(edge);
                        
                        // Reflect velocity vector
                        const dot = ball.vx * normal.x + ball.vy * normal.y;
                        ball.vx = ball.vx - 2 * dot * normal.x;
                        ball.vy = ball.vy - 2 * dot * normal.y;
                        
                        // Move ball outside collision
                        const overlap = ball.radius - distance;
                        ball.x += normal.x * overlap;
                        ball.y += normal.y * overlap;
                    }
                }
                
                // Add some gravity effect
                ball.vy += 0.05;
                
                // Damping to prevent infinite bouncing
                ball.vx *= 0.995;
                ball.vy *= 0.995;
            }
        }
        
        // Draw hexagon
        function drawHexagon(vertices) {
            ctx.beginPath();
            ctx.moveTo(vertices[0].x, vertices[0].y);
            
            for (let i = 1; i < 6; i++) {
                ctx.lineTo(vertices[i].x, vertices[i].y);
            }
            
            ctx.closePath();
            ctx.strokeStyle = 'rgba(76, 201, 240, 0.8)';
            ctx.lineWidth = 3;
            ctx.stroke();
            
            // Draw center point
            ctx.beginPath();
            ctx.arc(centerX, centerY, 5, 0, Math.PI * 2);
            ctx.fillStyle = '#4cc9f0';
            ctx.fill();
        }
        
        // Draw balls
        function drawBalls() {
            for (const ball of balls) {
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
                ctx.fillStyle = ball.color;
                ctx.fill();
                
                // Add shine effect
                ctx.beginPath();
                ctx.arc(ball.x - ball.radius/3, ball.y - ball.radius/3, ball.radius/3, 0, Math.PI * 2);
                ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
                ctx.fill();
            }
        }
        
        // Draw background effects
        function drawBackground() {
            // Draw grid
            ctx.strokeStyle = 'rgba(76, 201, 240, 0.05)';
            ctx.lineWidth = 1;
            
            // Vertical lines
            for (let x = 0; x < canvas.width; x += 30) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, canvas.height);
                ctx.stroke();
            }
            
            // Horizontal lines
            for (let y = 0; y < canvas.height; y += 30) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
                ctx.stroke();
            }
            
            // Draw center circle
            ctx.beginPath();
            ctx.arc(centerX, centerY, hexRadius - 20, 0, Math.PI * 2);
            ctx.strokeStyle = 'rgba(76, 201, 240, 0.1)';
            ctx.stroke();
        }
        
        // Animation loop
        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // Update hexagon rotation
            hexRotation += rotationSpeed;
            
            // Get hexagon vertices and edges
            const vertices = getHexagonVertices();
            const edges = getHexagonEdges(vertices);
            
            // Update and draw
            drawBackground();
            drawHexagon(vertices);
            updateBalls(edges);
            drawBalls();
            
            requestAnimationFrame(animate);
        }
        
        // Event listeners
        document.getElementById('speedUp').addEventListener('click', () => {
            rotationSpeed = Math.min(rotationSpeed + 0.002, 0.02);
        });
        
        document.getElementById('slowDown').addEventListener('click', () => {
            rotationSpeed = Math.max(rotationSpeed - 0.002, 0.001);
        });
        
        document.getElementById('reset').addEventListener('click', () => {
            balls.length = 0;
            initBalls(10);
            rotationSpeed = 0.005;
        });
        
        canvas.addEventListener('click', (e) => {
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // Create a ball at click position
            if (balls.length < maxBalls) {
                balls.push({
                    x: x,
                    y: y,
                    radius: 8 + Math.random() * 12,
                    vx: (Math.random() - 0.5) * 4,
                    vy: (Math.random() - 0.5) * 4,
                    color: colors[Math.floor(Math.random() * colors.length)]
                });
            }
        });
        
        // Initialize and start animation
        initBalls(10);
        animate();
    </script>
</body>
</html>
```

## Features of this Animation:

1. **Spinning Hexagon**: A blue hexagon rotates smoothly at the center of the canvas
2. **10 Bouncing Balls**: Colorful balls with random sizes and velocities bounce realistically inside the hexagon
3. **Physics Simulation**: Balls collide with the hexagon walls using proper reflection physics
4. **Interactive Controls**:
   - Speed Up: Increases hexagon rotation speed
   - Slow Down: Decreases hexagon rotation speed
   - Reset: Clears all balls and resets to initial state
5. **Click to Add Balls**: Click anywhere on the canvas to add more balls (up to 20)
6. **Visual Effects**: 
   - Subtle grid background
   - Ball shine effects
   - Smooth animations

The balls bounce realistically off the rotating hexagon walls, with gravity and damping effects to create natural-looking motion. The interface is clean and modern with a dark gradient background that makes the colorful balls stand out.
Anthropic

Claude 4 Sonnet (Non-reasoning)

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background: #1a1a2e;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            font-family: Arial, sans-serif;
        }
        canvas {
            border: 2px solid #00ff88;
            border-radius: 10px;
            box-shadow: 0 0 30px rgba(0, 255, 136, 0.3);
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="800" height="600"></canvas>

    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');

        // Hexagon properties
        const hexCenter = { x: canvas.width / 2, y: canvas.height / 2 };
        const hexRadius = 200;
        let hexRotation = 0;

        // Ball class
        class Ball {
            constructor() {
                this.x = hexCenter.x + (Math.random() - 0.5) * hexRadius;
                this.y = hexCenter.y + (Math.random() - 0.5) * hexRadius;
                this.vx = (Math.random() - 0.5) * 8;
                this.vy = (Math.random() - 0.5) * 8;
                this.radius = 8 + Math.random() * 12;
                this.color = `hsl(${Math.random() * 360}, 80%, 60%)`;
                this.trail = [];
            }

            update() {
                this.x += this.vx;
                this.y += this.vy;

                // Add current position to trail
                this.trail.push({ x: this.x, y: this.y });
                if (this.trail.length > 15) {
                    this.trail.shift();
                }

                // Check collision with hexagon walls
                this.checkHexagonCollision();
            }

            checkHexagonCollision() {
                const vertices = getHexagonVertices();
                
                for (let i = 0; i < vertices.length; i++) {
                    const current = vertices[i];
                    const next = vertices[(i + 1) % vertices.length];
                    
                    const collision = this.checkLineCollision(current, next);
                    if (collision) {
                        // Reflect velocity based on the wall normal
                        const wallVector = {
                            x: next.x - current.x,
                            y: next.y - current.y
                        };
                        const wallNormal = {
                            x: -wallVector.y,
                            y: wallVector.x
                        };
                        
                        // Normalize the normal vector
                        const length = Math.sqrt(wallNormal.x * wallNormal.x + wallNormal.y * wallNormal.y);
                        wallNormal.x /= length;
                        wallNormal.y /= length;
                        
                        // Reflect velocity
                        const dotProduct = this.vx * wallNormal.x + this.vy * wallNormal.y;
                        this.vx -= 2 * dotProduct * wallNormal.x;
                        this.vy -= 2 * dotProduct * wallNormal.y;
                        
                        // Move ball away from wall to prevent sticking
                        this.x += wallNormal.x * 2;
                        this.y += wallNormal.y * 2;
                        
                        break;
                    }
                }
            }

            checkLineCollision(p1, p2) {
                // Distance from point to line segment
                const A = this.x - p1.x;
                const B = this.y - p1.y;
                const C = p2.x - p1.x;
                const D = p2.y - p1.y;

                const dot = A * C + B * D;
                const lenSq = C * C + D * D;
                
                if (lenSq === 0) return false;
                
                let param = dot / lenSq;
                
                let xx, yy;
                if (param < 0) {
                    xx = p1.x;
                    yy = p1.y;
                } else if (param > 1) {
                    xx = p2.x;
                    yy = p2.y;
                } else {
                    xx = p1.x + param * C;
                    yy = p1.y + param * D;
                }

                const dx = this.x - xx;
                const dy = this.y - yy;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                return distance < this.radius;
            }

            draw() {
                // Draw trail
                ctx.globalAlpha = 0.3;
                for (let i = 0; i < this.trail.length - 1; i++) {
                    const alpha = i / this.trail.length;
                    ctx.globalAlpha = alpha * 0.3;
                    ctx.strokeStyle = this.color;
                    ctx.lineWidth = this.radius * alpha;
                    ctx.beginPath();
                    ctx.moveTo(this.trail[i].x, this.trail[i].y);
                    ctx.lineTo(this.trail[i + 1].x, this.trail[i + 1].y);
                    ctx.stroke();
                }
                
                // Draw ball
                ctx.globalAlpha = 1;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                
                // Gradient for 3D effect
                const gradient = ctx.createRadialGradient(
                    this.x - this.radius/3, this.y - this.radius/3, 0,
                    this.x, this.y, this.radius
                );
                gradient.addColorStop(0, 'white');
                gradient.addColorStop(0.3, this.color);
                gradient.addColorStop(1, this.color.replace('60%', '30%'));
                
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.strokeStyle = this.color.replace('60%', '40%');
                ctx.lineWidth = 2;
                ctx.stroke();
            }
        }

        // Get hexagon vertices based on current rotation
        function getHexagonVertices() {
            const vertices = [];
            for (let i = 0; i < 6; i++) {
                const angle = (i * Math.PI) / 3 + hexRotation;
                vertices.push({
                    x: hexCenter.x + Math.cos(angle) * hexRadius,
                    y: hexCenter.y + Math.sin(angle) * hexRadius
                });
            }
            return vertices;
        }

        // Draw hexagon
        function drawHexagon() {
            const vertices = getHexagonVertices();
            
            // Draw hexagon fill with gradient
            const gradient = ctx.createRadialGradient(
                hexCenter.x, hexCenter.y, 0,
                hexCenter.x, hexCenter.y, hexRadius
            );
            gradient.addColorStop(0, 'rgba(0, 255, 136, 0.1)');
            gradient.addColorStop(1, 'rgba(0, 255, 136, 0.05)');
            
            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.fillStyle = gradient;
            ctx.fill();
            
            // Draw hexagon outline with glow effect
            ctx.shadowColor = '#00ff88';
            ctx.shadowBlur = 10;
            ctx.strokeStyle = '#00ff88';
            ctx.lineWidth = 3;
            ctx.stroke();
            ctx.shadowBlur = 0;
        }

        // Create balls
        const balls = [];
        for (let i = 0; i < 10; i++) {
            balls.push(new Ball());
        }

        // Animation loop
        function animate() {
            // Clear canvas with fade effect
            ctx.fillStyle = 'rgba(26, 26, 46, 0.1)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // Update hexagon rotation
            hexRotation += 0.01;
            
            // Draw hexagon
            drawHexagon();
            
            // Update and draw balls
            balls.forEach(ball => {
                ball.update();
                ball.draw();
            });
            
            requestAnimationFrame(animate);
        }

        // Start animation
        animate();
    </script>
</body>
</html>
```
Google

Gemini 2.5 Pro

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in a Spinning Hexagon</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #0c0c0c;
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="animationCanvas"></canvas>

    <script>
        const canvas = document.getElementById('animationCanvas');
        const ctx = canvas.getContext('2d');

        let width = canvas.width = window.innerWidth;
        let height = canvas.height = window.innerHeight;

        // --- CONFIGURATION ---
        const NUM_BALLS = 10;
        const HEX_SIZE = Math.min(width, height) * 0.4; // Radius from center to a vertex
        const BALL_MAX_RADIUS = 18;
        const BALL_MIN_RADIUS = 10;
        const MAX_SPEED = 2.5;
        const ROTATION_SPEED = 0.003; // Radians per frame
        const HEX_LINE_WIDTH = 5;

        let hexagonAngle = 0;
        const balls = [];
        const center = { x: width / 2, y: height / 2 };

        // --- UTILITY FUNCTIONS ---
        function getRandom(min, max) {
            return Math.random() * (max - min) + min;
        }

        function getRandomColor() {
            const hue = Math.random() * 360;
            return `hsl(${hue}, 90%, 65%)`;
        }
        
        // --- BALL CLASS ---
        class Ball {
            constructor(x, y, vx, vy, radius, color) {
                this.x = x;
                this.y = y;
                this.vx = vx;
                this.vy = vy;
                this.radius = radius;
                this.color = color;
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
                ctx.closePath();
            }

            update(vertices) {
                // Move the ball
                this.x += this.vx;
                this.y += this.vy;

                // --- COLLISION DETECTION WITH HEXAGON WALLS ---
                for (let i = 0; i < 6; i++) {
                    const p1 = vertices[i];
                    const p2 = vertices[(i + 1) % 6];

                    // Calculate the normal vector of the hexagon side
                    // The vector (p2.y - p1.y, p1.x - p2.x) is perpendicular to the side
                    let normalX = p2.y - p1.y;
                    let normalY = p1.x - p2.x;

                    // Normalize the vector (make it a unit vector)
                    const length = Math.sqrt(normalX * normalX + normalY * normalY);
                    normalX /= length;
                    normalY /= length;

                    // Ensure the normal points outwards from the hexagon center
                    // We check this by taking the dot product of the normal with a vector from the center to the wall
                    const vecToWallX = p1.x - center.x;
                    const vecToWallY = p1.y - center.y;
                    if (vecToWallX * normalX + vecToWallY * normalY < 0) {
                        normalX *= -1;
                        normalY *= -1;
                    }

                    // Calculate the signed distance from the ball's center to the line (wall)
                    const vecToBallX = this.x - p1.x;
                    const vecToBallY = this.y - p1.y;
                    const distance = vecToBallX * normalX + vecToBallY * normalY;

                    // If the distance is less than the ball's radius, a collision has occurred
                    if (distance > -this.radius) {
                        // 1. Correct position to prevent sinking into the wall
                        const overlap = this.radius + distance;
                        this.x -= overlap * normalX;
                        this.y -= overlap * normalY;

                        // 2. Reflect the velocity vector
                        const dotProduct = this.vx * normalX + this.vy * normalY;
                        this.vx -= 2 * dotProduct * normalX;
                        this.vy -= 2 * dotProduct * normalY;
                    }
                }
            }
        }

        // --- HEXAGON FUNCTIONS ---
        function getHexagonVertices(angle) {
            const vertices = [];
            for (let i = 0; i < 6; i++) {
                const currentAngle = angle + (i * Math.PI / 3); // 60 degrees in radians
                vertices.push({
                    x: center.x + HEX_SIZE * Math.cos(currentAngle),
                    y: center.y + HEX_SIZE * Math.sin(currentAngle)
                });
            }
            return vertices;
        }

        function drawHexagon(vertices) {
            ctx.beginPath();
            ctx.moveTo(vertices[0].x, vertices[0].y);
            for (let i = 1; i < 6; i++) {
                ctx.lineTo(vertices[i].x, vertices[i].y);
            }
            ctx.closePath();

            ctx.lineWidth = HEX_LINE_WIDTH;
            ctx.strokeStyle = '#66fcf1';
            ctx.stroke();

            // Add a subtle glow effect
            ctx.shadowBlur = 20;
            ctx.shadowColor = '#66fcf1';
            ctx.stroke();
            ctx.shadowBlur = 0;
        }

        // --- INITIALIZATION ---
        function init() {
            balls.length = 0; // Clear the existing balls array
            const apothem = HEX_SIZE * Math.sqrt(3) / 2; // Inner radius of the hexagon

            for (let i = 0; i < NUM_BALLS; i++) {
                const radius = getRandom(BALL_MIN_RADIUS, BALL_MAX_RADIUS);
                
                // Ensure balls are spawned inside the hexagon
                const r = getRandom(0, apothem - radius);
                const angle = getRandom(0, Math.PI * 2);
                
                const x = center.x + r * Math.cos(angle);
                const y = center.y + r * Math.sin(angle);
                
                const vx = getRandom(-MAX_SPEED, MAX_SPEED);
                const vy = getRandom(-MAX_SPEED, MAX_SPEED);
                const color = getRandomColor();
                balls.push(new Ball(x, y, vx, vy, radius, color));
            }
        }

        // --- ANIMATION LOOP ---
        function animate() {
            requestAnimationFrame(animate);
            ctx.fillStyle = 'rgba(12, 12, 12, 0.25)'; // Fading effect
            ctx.fillRect(0, 0, width, height);

            // Update hexagon rotation and get current vertices
            hexagonAngle += ROTATION_SPEED;
            const vertices = getHexagonVertices(hexagonAngle);

            // Update and draw balls
            balls.forEach(ball => {
                ball.update(vertices);
                ball.draw();
            });
            
            // Draw hexagon on top of balls
            drawHexagon(vertices);
        }

        // --- EVENT LISTENERS ---
        window.addEventListener('resize', () => {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
            center.x = width / 2;
            center.y = height / 2;
            init(); // Re-initialize on resize
        });

        // --- S T A R T ---
        init();
        animate();

    </script>
</body>
</html>
```
Alibaba

Qwen3 235B A22B (Non-reasoning)

最终回答
```html
<!DOCTYPE html>
<html>
<head>
  <title>Spinning Hexagon with Bouncing Balls</title>
  <style>
    html, body {
      margin: 0;
      overflow: hidden;
      background: #000;
      width: 100vw;
      height: 100vh;
    }
    svg {
      display: block;
    }
  </style>
</head>
<body>
  <svg id="svg" width="100%" height="100%"></svg>
  <script>
    const svg = document.getElementById('svg');
    const W = window.innerWidth;
    const H = window.innerHeight;
    const CENTER_X = W / 2;
    const CENTER_Y = H / 2;
    const HEX_RADIUS = Math.min(W, H) * 0.4;
    const BALL_COUNT = 10;
    let lastTime = performance.now();
    
    svg.setAttribute('viewBox', `0 0 ${W} ${H}`);
    svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');

    // Create hexagon
    const hex = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
    hex.setAttribute('stroke', 'white');
    hex.setAttribute('fill', 'none');
    hex.setAttribute('stroke-width', '2');
    svg.appendChild(hex);

    // Create ball elements
    const balls = [];
    const ballElements = [];
    
    for (let i = 0; i < BALL_COUNT; i++) {
      balls.push({
        x: CENTER_X,
        y: CENTER_Y,
        vx: (Math.random() - 0.5) * 6,
        vy: (Math.random() - 0.5) * 6,
        r: 8
      });
      
      const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
      circle.setAttribute('fill', 'white');
      svg.appendChild(circle);
      ballElements.push(circle);
    }

    let theta = 0;
    const HEX_DELTA = 0.6 * Math.PI / 180; // Rotation speed

    function getHexagonVertices(cx, cy, r, theta) {
      const vertices = [];
      for (let i = 0; i < 6; i++) {
        const angle = theta + i * (Math.PI / 3);
        vertices.push({
          x: cx + r * Math.cos(angle),
          y: cy + r * Math.sin(angle)
        });
      }
      return vertices;
    }

    function checkCollision(ball) {
      const vertices = getHexagonVertices(CENTER_X, CENTER_Y, HEX_RADIUS, theta);
      let maxPen = 0;
      let normal = null;

      for (let i = 0; i < 6; i++) {
        const p1 = vertices[i];
        const p2 = vertices[(i + 1) % 6];
        
        const dx = p2.x - p1.x;
        const dy = p2.y - p1.y;
        
        // Normal pointing inward
        let nx = -dy;
        let ny = dx;
        const len = Math.hypot(nx, ny);
        if (len === 0) continue;
        nx /= len;
        ny /= len;

        const dp = (ball.x - p1.x) * nx + (ball.y - p1.y) * ny;
        const pen = ball.r + dp;
        
        if (dp < 0 && pen > 0) {
          if (pen > maxPen) {
            maxPen = pen;
            normal = { x: nx, y: ny };
          }
        }
      }
      
      if (normal) {
        const dot = ball.vx * normal.x + ball.vy * normal.y;
        ball.vx = ball.vx - 2 * dot * normal.x;
        ball.vy = ball.vy - 2 * dot * normal.y;
        
        // Push out
        const adjust = 1.05;
        ball.x += normal.x * maxPen * adjust;
        ball.y += normal.y * maxPen * adjust;
      }
    }

    function update() {
      // Update timing
      const now = performance.now();
      const dt = now - lastTime;
      lastTime = now;
      
      // Rotate hexagon
      theta += HEX_DELTA;
      
      // Update ball positions
      balls.forEach(ball => {
        ball.x += ball.vx;
        ball.y += ball.vy;
        checkCollision(ball);
      });
      
      // Draw hexagon
      const points = getHexagonVertices(CENTER_X, CENTER_Y, HEX_RADIUS, theta)
        .map(p => `${p.x},${p.y}`).join(' ');
      hex.setAttribute('points', points);
      
      // Draw balls
      balls.forEach((b, i) => {
        ballElements[i].setAttribute('cx', b.x);
        ballElements[i].setAttribute('cy', b.y);
        ballElements[i].setAttribute('r', b.r);
      });
      
      requestAnimationFrame(update);
    }

    update();
  </script>
</body>
</html>
```
Mistral

Mistral Medium 3

最终回答
Here's a complete HTML file with an animation of 10 balls bouncing inside a spinning hexagon using JavaScript and the HTML Canvas API:

```html
<!DOCTYPE html>
<html>
<head>
    <title>Bouncing Balls in a Spinning Hexagon</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            overflow: hidden;
        }
        canvas {
            border: 1px solid #000;
            background-color: #fff;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const width = canvas.width;
        const height = canvas.height;

        // Hexagon properties
        let hexagonRotation = 0;
        const hexagonRadius = 200;
        const hexagonSides = 6;
        const hexagonRotationSpeed = 0.01;

        // Ball properties
        const balls = [];
        const ballRadius = 10;
        const ballColors = ['#FF5733', '#33FF57', '#3357FF', '#F3FF33', '#FF33F3', '#33FFF3', '#8A2BE2', '#FF7F50', '#6495ED', '#DC143C'];

        // Initialize balls
        for (let i = 0; i < 10; i++) {
            const angle = (i * (2 * Math.PI / 10)) + (Math.random() * 0.1);
            const distance = hexagonRadius * 0.7;
            balls.push({
                x: width / 2 + Math.cos(angle) * distance,
                y: height / 2 + Math.sin(angle) * distance,
                vx: Math.cos(angle) * 2,
                vy: Math.sin(angle) * 2,
                color: ballColors[i]
            });
        }

        // Function to draw a hexagon
        function drawHexagon() {
            ctx.beginPath();
            for (let i = 0; i < hexagonSides; i++) {
                const angle = (i * (2 * Math.PI / hexagonSides)) + hexagonRotation;
                const x = width / 2 + Math.cos(angle) * hexagonRadius;
                const y = height / 2 + Math.sin(angle) * hexagonRadius;
                if (i === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            ctx.closePath();
            ctx.strokeStyle = '#000';
            ctx.lineWidth = 2;
            ctx.stroke();
        }

        // Function to draw balls
        function drawBalls() {
            balls.forEach(ball => {
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);
                ctx.fillStyle = ball.color;
                ctx.fill();
                ctx.closePath();
            });
        }

        // Function to update ball positions
        function updateBalls() {
            balls.forEach(ball => {
                ball.x += ball.vx;
                ball.y += ball.vy;

                // Check for collisions with hexagon edges
                for (let i = 0; i < hexagonSides; i++) {
                    const angle1 = (i * (2 * Math.PI / hexagonSides)) + hexagonRotation;
                    const angle2 = (((i + 1) % hexagonSides) * (2 * Math.PI / hexagonSides)) + hexagonRotation;
                    const x1 = width / 2 + Math.cos(angle1) * hexagonRadius;
                    const y1 = height / 2 + Math.sin(angle1) * hexagonRadius;
                    const x2 = width / 2 + Math.cos(angle2) * hexagonRadius;
                    const y2 = height / 2 + Math.sin(angle2) * hexagonRadius;

                    // Check for collision with this edge
                    const collision = checkLineCollision(ball.x, ball.y, ballRadius, x1, y1, x2, y2);
                    if (collision) {
                        // Reflect the ball's velocity
                        const normal = { x: -(y2 - y1), y: x2 - x1 };
                        const length = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
                        normal.x /= length;
                        normal.y /= length;

                        const dot = ball.vx * normal.x + ball.vy * normal.y;
                        ball.vx = ball.vx - 2 * dot * normal.x;
                        ball.vy = ball.vy - 2 * dot * normal.y;
                    }
                }
            });
        }

        // Function to check collision between a ball and a line
        function checkLineCollision(ballX, ballY, ballRadius, x1, y1, x2, y2) {
            const lineLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
            const dot = ((ballX - x1) * (x2 - x1) + (ballY - y1) * (y2 - y1)) / (lineLength * lineLength);
            let closestX = x1 + dot * (x2 - x1);
            let closestY = y1 + dot * (y2 - y1);

            if (dot < 0) {
                closestX = x1;
                closestY = y1;
            } else if (dot > 1) {
                closestX = x2;
                closestY = y2;
            }

            const distance = Math.sqrt((ballX - closestX) * (ballX - closestX) + (ballY - closestY) * (ballY - closestY));
            return distance <= ballRadius;
        }

        // Animation loop
        function animate() {
            ctx.clearRect(0, 0, width, height);
            drawHexagon();
            drawBalls();
            updateBalls();
            hexagonRotation += hexagonRotationSpeed;
            requestAnimationFrame(animate);
        }

        // Start animation
        animate();
    </script>
</body>
</html>
```

This code creates a canvas with a spinning hexagon and 10 bouncing balls inside it. The balls change direction when they collide with the edges of the hexagon. The animation is smooth and should work well in modern web browsers.
OpenAI

o3

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spinning Hexagon – Bouncing Balls</title>
<style>
    html,body{
        margin:0;
        height:100%;
        background:#111;
        overflow:hidden;
        display:flex;
        align-items:center;
        justify-content:center;
    }
    canvas{
        background:#111;
    }
</style>
</head>
<body>
<canvas id="stage" width="640" height="640"></canvas>

<script>
/* -------------------------------------------------
   Utility helpers
---------------------------------------------------*/
function length(v){ return Math.hypot(v.x, v.y); }
function normalize(v){
    const l = length(v);
    return {x: v.x/l, y: v.y/l};
}
function dot(a,b){ return a.x*b.x + a.y*b.y; }

/* -------------------------------------------------
   Core objects
---------------------------------------------------*/
const canvas  = document.getElementById('stage');
const ctx     = canvas.getContext('2d');
const W       = canvas.width;
const H       = canvas.height;
const CENTER  = {x: W/2, y: H/2};

const HEX_RADIUS   = 250;
const BALL_RADIUS  = 8;
const BALL_COUNT   = 10;
const ROT_SPEED    = 0.012;   // radians per frame

let   hexAngle     = 0;       // current rotation

/* -------------------------------------------------
   Build hexagon (unit, centered at 0/0)
---------------------------------------------------*/
function makeHexVertices(angle){
    const verts = [];
    for(let i=0;i<6;i++){
        const a = angle + i*Math.PI/3;   // 60° steps
        verts.push({
            x: CENTER.x + Math.cos(a)*HEX_RADIUS,
            y: CENTER.y + Math.sin(a)*HEX_RADIUS
        });
    }
    return verts;
}

/* -------------------------------------------------
   Collision helpers
---------------------------------------------------*/
function reflectVelocity(vel, normal){
    // v' = v - 2 (v·n) n
    const vn = dot(vel,normal);
    return {
        x: vel.x - 2*vn*normal.x,
        y: vel.y - 2*vn*normal.y
    };
}

/* -------------------------------------------------
   Ball definition
---------------------------------------------------*/
class Ball{
    constructor(pos, vel){
        this.pos = pos;   // {x,y}
        this.vel = vel;   // {x,y}
        this.r   = BALL_RADIUS;
        this.color = `hsl(${Math.random()*360},80%,60%)`;
    }

    update(){
        this.pos.x += this.vel.x;
        this.pos.y += this.vel.y;
    }

    draw(ctx){
        ctx.beginPath();
        ctx.arc(this.pos.x, this.pos.y, this.r, 0, Math.PI*2);
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}

/* -------------------------------------------------
   Build initial set of balls
---------------------------------------------------*/
function randomPointInHex(){
    let p;
    while(true){
        p = {
            x: CENTER.x + (Math.random()*2-1)*HEX_RADIUS,
            y: CENTER.y + (Math.random()*2-1)*HEX_RADIUS
        };
        if(pointInHex(p, makeHexVertices(hexAngle))) return p;
    }
}

function pointInHex(p, verts){
    for(let i=0;i<6;i++){
        const v1 = verts[i];
        const v2 = verts[(i+1)%6];
        const edge = {x: v2.x - v1.x, y: v2.y - v1.y};
        const rel  = {x: p.x - v1.x, y: p.y - v1.y};
        const cross = edge.x*rel.y - edge.y*rel.x;
        if(cross < 0) return false;
    }
    return true;
}

const balls = [];
for(let i=0;i<BALL_COUNT;i++){
    const p = randomPointInHex();
    const speed = 2 + Math.random()*1.5;
    const angle = Math.random()*Math.PI*2;
    balls.push(new Ball(
        p,
        {x: Math.cos(angle)*speed, y: Math.sin(angle)*speed}
    ));
}

/* -------------------------------------------------
   Animation loop
---------------------------------------------------*/
function tick(){
    requestAnimationFrame(tick);

    // advance rotation
    hexAngle += ROT_SPEED;
    const verts = makeHexVertices(hexAngle);

    // update and collide balls ----------------------------------------
    for(const ball of balls){
        ball.update();

        // check against each hex edge
        for(let i=0;i<6;i++){
            const v1 = verts[i];
            const v2 = verts[(i+1)%6];

            const edge = {x: v2.x - v1.x, y: v2.y - v1.y};
            const len  = length(edge);
            // inward normal (make sure it points inside)
            let normal = normalize({x: -edge.y, y:  edge.x});
            const toCenter = {x: CENTER.x - v1.x, y: CENTER.y - v1.y};
            if(dot(normal, toCenter) < 0){
                normal.x *= -1;
                normal.y *= -1;
            }

            // signed distance from ball center to edge
            const rel   = {x: ball.pos.x - v1.x, y: ball.pos.y - v1.y};
            const dist  = dot(rel, normal);

            if(dist < ball.r){       // collision / penetration
                // slide out of wall
                const penetration = ball.r - dist;
                ball.pos.x += normal.x * penetration;
                ball.pos.y += normal.y * penetration;

                // reflect velocity if heading towards wall
                if(dot(ball.vel, normal) < 0){
                    ball.vel = reflectVelocity(ball.vel, normal);
                }
            }
        }
    }

    // --------------- render -----------------------------------------
    ctx.clearRect(0,0,W,H);

    // draw spinning hexagon
    ctx.save();
    ctx.translate(CENTER.x, CENTER.y);
    ctx.rotate(hexAngle);
    ctx.beginPath();
    for(let i=0;i<6;i++){
        const a = i*Math.PI/3;
        const x = Math.cos(a)*HEX_RADIUS;
        const y = Math.sin(a)*HEX_RADIUS;
        if(i===0) ctx.moveTo(x,y);
        else      ctx.lineTo(x,y);
    }
    ctx.closePath();
    ctx.lineWidth = 4;
    ctx.strokeStyle = '#08f';
    ctx.stroke();
    ctx.restore();

    // draw balls
    for(const ball of balls) ball.draw(ctx);
}

tick();
</script>
</body>
</html>
```
OpenAI

GPT-4.1

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Bouncing Balls in Spinning Hexagon</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      background: #202030;
      overflow: hidden;
      height: 100%;
    }
    canvas {
      display: block;
      background: #282844;
    }
  </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

function resize() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();

const HEX_RADIUS = Math.min(canvas.width, canvas.height) * 0.33;
const BALL_RADIUS = 18;
const NUM_BALLS = 10;
const SPIN_SPEED = 0.7 * Math.PI / 180; // radians per frame

function hexagonVertices(cx, cy, radius, rot) {
  let verts = [];
  for (let i = 0; i < 6; i++) {
    let angle = rot + Math.PI/6 + i * Math.PI/3;
    verts.push({
      x: cx + radius * Math.cos(angle),
      y: cy + radius * Math.sin(angle)
    });
  }
  return verts;
}

function pointLineDist(px, py, x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  const len2 = dx * dx + dy * dy;
  const t = Math.max(0, Math.min(1, ((px - x1) * dx + (py - y1) * dy) / len2));
  const projx = x1 + t * dx;
  const projy = y1 + t * dy;
  const dist = Math.hypot(px - projx, py - projy);
  return {dist, projx, projy};
}

function insideHex(point, hexVerts) {
  // Use crossing number algorithm
  let cnt = 0;
  for (let i = 0; i < 6; i++) {
    const v1 = hexVerts[i];
    const v2 = hexVerts[(i+1)%6];

    if ((v1.y > point.y) !== (v2.y > point.y)) {
      let atX = (v2.x - v1.x) * (point.y - v1.y) / (v2.y - v1.y) + v1.x;
      if (point.x < atX) cnt++;
    }
  }
  return cnt % 2 === 1;
}

// Random pastel color generator
function randomColor() {
  const base = 150;
  const variance = 105;
  const r = Math.floor(base + Math.random() * variance);
  const g = Math.floor(base + Math.random() * variance);
  const b = Math.floor(base + Math.random() * variance);
  return `rgba(${r},${g},${b},0.82)`;
}

// Ball Object
class Ball {
  constructor(x, y, vx, vy, color) {
    this.x = x; this.y = y;
    this.vx = vx; this.vy = vy;
    this.color = color;
  }
  update() {
    this.x += this.vx;
    this.y += this.vy;
  }
  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, BALL_RADIUS, 0, 2*Math.PI);
    ctx.fillStyle = this.color;
    ctx.shadowColor = this.color;
    ctx.shadowBlur = 16;
    ctx.fill();
    ctx.shadowBlur = 0;
  }
}

// Place balls randomly inside hexagon
function randomPointInHex(cx, cy, r, rot) {
  // Rejection method
  while (true) {
    let a = Math.random() * 2 * Math.PI;
    let d = Math.random() * r * 0.92; // keep some margin
    let px = cx + d * Math.cos(a);
    let py = cy + d * Math.sin(a);
    let verts = hexagonVertices(cx, cy, r - BALL_RADIUS, rot);
    if (insideHex({x: px, y: py}, verts)) {
      return {x: px, y: py};
    }
  }
}

let hexRot = 0;
let cx = canvas.width/2, cy = canvas.height/2;
let balls = [];

function initBalls() {
  balls = [];
  for (let i = 0; i < NUM_BALLS; i++) {
    let pt = randomPointInHex(cx, cy, HEX_RADIUS - BALL_RADIUS, 0);
    // velocity random direction & speed
    let angle = Math.random()*2*Math.PI;
    let speed = 2 + Math.random()*1.8;
    balls.push(new Ball(
      pt.x, pt.y,
      Math.cos(angle)*speed, Math.sin(angle)*speed,
      randomColor()
    ));
  }
}
initBalls();

function handleResize() {
  cx = canvas.width/2;
  cy = canvas.height/2;
}
window.addEventListener('resize', () => {
  handleResize();
  initBalls();
});

function reflectVelocity(vx, vy, nx, ny) {
  // nx,ny must be normalized
  // Reflect v about normal n
  let dot = vx*nx + vy*ny;
  // bounce coefficient
  const f = 0.98;
  return {
    vx: (vx - 2 * dot * nx) * f,
    vy: (vy - 2 * dot * ny) * f
  };
}

function animate() {
  ctx.clearRect(0,0,canvas.width, canvas.height);
  // Draw spinning hexagon
  let verts = hexagonVertices(cx, cy, HEX_RADIUS, hexRot);

  ctx.save();
  ctx.beginPath();
  verts.forEach((v, i) => {
    if (i===0) ctx.moveTo(v.x, v.y);
    else ctx.lineTo(v.x, v.y);
  });
  ctx.closePath();
  ctx.lineWidth = 7;
  ctx.shadowColor = "#acf";
  ctx.shadowBlur = 14;
  ctx.strokeStyle = "#40a0e0";
  ctx.stroke();
  ctx.shadowBlur = 0;
  ctx.restore();

  // Draw balls and update their physics
  // Find collision with moving polygon
  for (let ball of balls) {
    // Store previous position
    ball.update();

    // For each edge: find if ball goes outside hex
    let coll = false;
    for (let i = 0; i < 6; i++) {
      const v1 = verts[i];
      const v2 = verts[(i+1)%6];
      // Compute distance from ball center to edge
      let {dist, projx, projy} = pointLineDist(ball.x, ball.y, v1.x, v1.y, v2.x, v2.y);
      // To check if projection is within edge segment and inside hex-normal
      let edgeDir = {x: v2.x-v1.x, y: v2.y-v1.y};
      let edgeLen = Math.hypot(edgeDir.x, edgeDir.y);
      let edgeNorm = {x: edgeDir.x/edgeLen, y: edgeDir.y/edgeLen};
      let normal = {x: edgeNorm.y, y: -edgeNorm.x}; // outward normal per hex order

      // Vector from edge to ball center
      let fromEdge = {x: ball.x-projx, y: ball.y-projy};
      // Check if ball center is pushing outwards
      let outwards = (fromEdge.x * normal.x + fromEdge.y * normal.y) > 0.1;

      // Projection must be on the segment, and pushing outside, and distance less than radius
      let inSegment = ((projx - v1.x)*(projx-v2.x) + (projy-v1.y)*(projy-v2.y)) <= 0.01;
      if (dist < BALL_RADIUS - 0.1 && inSegment && outwards) {
        // Move it back to tangent point
        let pushback = BALL_RADIUS - dist + 0.7;
        ball.x += normal.x * pushback;
        ball.y += normal.y * pushback;
        // Reflect velocity
        let reflected = reflectVelocity(ball.vx, ball.vy, normal.x, normal.y);
        ball.vx = reflected.vx;
        ball.vy = reflected.vy;
        coll = true;
      }
    }

    // If ball fully left hex (rare): bring back into center
    if (!insideHex({x: ball.x, y: ball.y}, verts)) {
      let towards = Math.atan2(cy - ball.y, cx - ball.x);
      ball.x = cx + (HEX_RADIUS - BALL_RADIUS*1.2)*Math.cos(towards);
      ball.y = cy + (HEX_RADIUS - BALL_RADIUS*1.2)*Math.sin(towards);
      ball.vx = Math.cos(towards + Math.PI/2)*(2+Math.random()) * (Math.random()<.5 ? 1 : -1);
      ball.vy = Math.sin(towards + Math.PI/2)*(2+Math.random()) * (Math.random()<.5 ? 1 : -1);
    }
    ball.draw(ctx);
  }

  hexRot += SPIN_SPEED;
  requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>
```
Cohere

Command A

最终回答
Below is an HTML file with JavaScript code to create an animation of 10 balls bouncing inside a spinning hexagon. The animation uses the HTML5 Canvas API.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            background-color: #fff;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');

        const canvasSize = Math.min(canvas.width, canvas.height);
        const hexagonSize = canvasSize * 0.8;
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const ballCount = 10;
        const balls = [];
        const rotationSpeed = 0.01;

        class Ball {
            constructor() {
                this.radius = 10;
                this.angle = Math.random() * Math.PI * 2;
                this.distance = (hexagonSize / 2) * 0.8 * (0.5 + Math.random() * 0.5);
                this.speed = 1 + Math.random() * 2;
                this.color = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
            }

            update() {
                this.angle += this.speed / 100;
                if (this.angle > Math.PI * 2) this.angle -= Math.PI * 2;
            }

            draw(rotation) {
                const x = centerX + this.distance * Math.cos(this.angle + rotation);
                const y = centerY + this.distance * Math.sin(this.angle + rotation);
                ctx.beginPath();
                ctx.arc(x, y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
            }
        }

        function drawHexagon(rotation) {
            ctx.beginPath();
            for (let i = 0; i < 6; i++) {
                const angle = Math.PI / 3 * i + rotation;
                const x = centerX + hexagonSize * Math.cos(angle);
                const y = centerY + hexagonSize * Math.sin(angle);
                if (i === 0) ctx.moveTo(x, y);
                else ctx.lineTo(x, y);
            }
            ctx.closePath();
            ctx.strokeStyle = '#000';
            ctx.lineWidth = 2;
            ctx.stroke();
        }

        function initBalls() {
            for (let i = 0; i < ballCount; i++) {
                balls.push(new Ball());
            }
        }

        function animate(timestamp) {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            const rotation = timestamp * rotationSpeed;

            drawHexagon(rotation);

            balls.forEach(ball => {
                ball.update();
                ball.draw(rotation);
            });

            requestAnimationFrame(animate);
        }

        initBalls();
        animate(0);
    </script>
</body>
</html>
```

This code creates a responsive animation with the following features:

1.  A spinning hexagon that rotates slowly.
2.  10 balls bouncing inside the hexagon, each with a random color, size, and speed.
3.  The balls move in a circular pattern, giving the illusion of bouncing.

The animation is created using the HTML5 Canvas API and is updated at each frame using the `requestAnimationFrame` function. The balls and hexagon are drawn using basic geometric shapes and transformed using rotation and translation.

To run this code, simply open the HTML file in a web browser. The animation will start automatically and continue indefinitely.
SpaceXAI

Grok 4

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #f0f0f0; }
        canvas { border: 1px solid #000; }
    </style>
</head>
<body>
    <canvas id="canvas" width="500" height="500"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const cx = 250;
        const cy = 250;
        const R = 200;
        const numBalls = 10;
        const ballRadius = 5;
        const omega = Math.PI / 2; // radians per second, full spin in 4 seconds
        const maxSpeed = 200; // pixels per second

        let angle = 0;
        let lastTime = 0;
        let balls = [];

        // Function to check if point is in polygon (ray casting)
        function isPointInPolygon(x, y, verts) {
            let inside = false;
            let n = verts.length;
            for (let i = 0, j = n - 1; i < n; j = i++) {
                let xi = verts[i].x, yi = verts[i].y;
                let xj = verts[j].x, yj = verts[j].y;
                if ((yi > y) !== (yj > y) && (x < (xj - xi) * (y - yi) / (yj - yi + 1e-6) + xi)) {
                    inside = !inside;
                }
            }
            return inside;
        }

        // Initialize balls
        function initBalls() {
            // Compute initial vertices at angle 0
            let initVerts = [];
            for (let i = 0; i < 6; i++) {
                let theta = 2 * Math.PI * i / 6;
                initVerts.push({
                    x: cx + R * Math.cos(theta),
                    y: cy + R * Math.sin(theta)
                });
            }
            for (let b = 0; b < numBalls; b++) {
                let x, y;
                do {
                    let dist = R * 0.9 * Math.random();
                    let ang = Math.random() * 2 * Math.PI;
                    x = cx + dist * Math.cos(ang);
                    y = cy + dist * Math.sin(ang);
                } while (!isPointInPolygon(x, y, initVerts));
                let vx = (Math.random() - 0.5) * 2 * maxSpeed;
                let vy = (Math.random() - 0.5) * 2 * maxSpeed;
                let color = `hsl(${Math.random() * 360}, 100%, 50%)`;
                balls.push({x, y, vx, vy, color});
            }
        }

        // Get current vertices and sides
        function getHexagon(angle) {
            let verts = [];
            let sides = [];
            for (let i = 0; i < 6; i++) {
                let theta = angle + 2 * Math.PI * i / 6;
                verts.push({
                    x: cx + R * Math.cos(theta),
                    y: cy + R * Math.sin(theta)
                });
            }
            for (let i = 0; i < 6; i++) {
                let j = (i + 1) % 6;
                sides.push({
                    x1: verts[i].x, y1: verts[i].y,
                    x2: verts[j].x, y2: verts[j].y
                });
            }
            return {verts, sides};
        }

        // Animation loop
        function animate(time) {
            if (!lastTime) lastTime = time;
            const dt = (time - lastTime) / 1000;
            lastTime = time;

            angle += omega * dt;

            const {verts, sides} = getHexagon(angle);

            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Draw hexagon
            ctx.beginPath();
            ctx.moveTo(verts[0].x, verts[0].y);
            for (let i = 1; i < 6; i++) {
                ctx.lineTo(verts[i].x, verts[i].y);
            }
            ctx.closePath();
            ctx.strokeStyle = 'black';
            ctx.lineWidth = 2;
            ctx.stroke();

            // Update and draw balls
            balls.forEach(ball => {
                const old_x = ball.x;
                const old_y = ball.y;
                let tent_x = old_x + ball.vx * dt;
                let tent_y = old_y + ball.vy * dt;

                let min_t = Infinity;
                let intersect_side = -1;
                let ix, iy;

                for (let s = 0; s < 6; s++) {
                    const side = sides[s];
                    const dx = tent_x - old_x;
                    const dy = tent_y - old_y;
                    const dsx = side.x2 - side.x1;
                    const dsy = side.y2 - side.y1;
                    const den = dsx * dy - dsy * dx;
                    if (Math.abs(den) < 1e-6) continue;
                    const t = ((side.x1 - old_x) * dsy - (side.y1 - old_y) * dsx) / den;
                    const u = ((side.x1 - old_x) * dy - (side.y1 - old_y) * dx) / den;
                    if (t > 0 && t < min_t && u >= 0 && u <= 1) {
                        min_t = t;
                        intersect_side = s;
                        ix = old_x + t * dx;
                        iy = old_y + t * dy;
                    }
                }

                if (intersect_side !== -1) {
                    // Compute wall velocity at intersection
                    const rx = ix - cx;
                    const ry = iy - cy;
                    const wall_vx = -omega * ry;
                    const wall_vy = omega * rx;

                    // Compute inward normal
                    const side = sides[intersect_side];
                    const dsx = side.x2 - side.x1;
                    const dsy = side.y2 - side.y1;
                    let n1x = -dsy;
                    let n1y = dsx;
                    const mx = (side.x1 + side.x2) / 2;
                    const my = (side.y1 + side.y2) / 2;
                    const to_center_x = cx - mx;
                    const to_center_y = cy - my;
                    const dot1 = n1x * to_center_x + n1y * to_center_y;
                    let nx = dot1 > 0 ? n1x : dsy;
                    let ny = dot1 > 0 ? n1y : -dsx;
                    const len = Math.sqrt(nx * nx + ny * ny);
                    nx /= len;
                    ny /= len;

                    // Reflect with moving wall
                    const wall_n = wall_vx * nx + wall_vy * ny;
                    const ball_n = ball.vx * nx + ball.vy * ny;
                    const dot = ball_n - wall_n;
                    ball.vx -= 2 * dot * nx;
                    ball.vy -= 2 * dot * ny;

                    // Update position for remaining time
                    ball.x = ix + ball.vx * (1 - min_t) * dt;
                    ball.y = iy + ball.vy * (1 - min_t) * dt;
                } else {
                    ball.x = tent_x;
                    ball.y = tent_y;
                }

                // Draw ball
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ballRadius, 0, 2 * Math.PI);
                ctx.fillStyle = ball.color;
                ctx.fill();
            });

            requestAnimationFrame(animate);
        }

        initBalls();
        requestAnimationFrame(animate);
    </script>
</body>
</html>
```
DeepSeek

DeepSeek V3 0324

最终回答
Here's a complete HTML file with JavaScript that creates an animation of 10 balls bouncing inside a spinning hexagon:

```html
<!DOCTYPE html>
<html>
<head>
    <title>Bouncing Balls in Spinning Hexagon</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');
        
        // Set canvas size
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const hexagonRadius = Math.min(canvas.width, canvas.height) * 0.4;
        let hexagonAngle = 0;
        
        // Create balls
        const balls = [];
        const ballCount = 10;
        const ballRadius = 15;
        
        for (let i = 0; i < ballCount; i++) {
            balls.push({
                x: Math.random() * (canvas.width - 2 * ballRadius) + ballRadius,
                y: Math.random() * (canvas.height - 2 * ballRadius) + ballRadius,
                dx: (Math.random() - 0.5) * 8,
                dy: (Math.random() - 0.5) * 8,
                color: `hsl(${Math.random() * 360}, 80%, 60%)`
            });
        }
        
        function drawHexagon(radius, angle) {
            ctx.save();
            ctx.translate(centerX, centerY);
            ctx.rotate(angle);
            
            ctx.beginPath();
            for (let i = 0; i < 6; i++) {
                const x = radius * Math.cos(i * Math.PI / 3);
                const y = radius * Math.sin(i * Math.PI / 3);
                if (i === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            ctx.closePath();
            ctx.strokeStyle = '#fff';
            ctx.lineWidth = 3;
            ctx.stroke();
            
            ctx.restore();
        }
        
        function isPointInHexagon(x, y, radius, angle) {
            // Transform point to hexagon's coordinate space
            const dx = x - centerX;
            const dy = y - centerY;
            const cos = Math.cos(-angle);
            const sin = Math.sin(-angle);
            const tx = dx * cos - dy * sin;
            const ty = dx * sin + dy * cos;
            
            // Check if point is inside hexagon
            const sideLength = radius;
            const height = sideLength * Math.sqrt(3) / 2;
            const width = sideLength * 2;
            
            if (Math.abs(tx) > width / 2) return false;
            if (Math.abs(ty) > height) return false;
            
            const slope = height / (width / 2);
            const boundary = height - slope * Math.abs(tx);
            
            return Math.abs(ty) <= boundary;
        }
        
        function updateBalls() {
            for (let ball of balls) {
                // Update position
                ball.x += ball.dx;
                ball.y += ball.dy;
                
                // Check collision with hexagon
                const nextX = ball.x + ball.dx;
                const nextY = ball.y + ball.dy;
                
                if (!isPointInHexagon(nextX, ball.y, hexagonRadius, hexagonAngle)) {
                    ball.dx *= -1;
                }
                
                if (!isPointInHexagon(ball.x, nextY, hexagonRadius, hexagonAngle)) {
                    ball.dy *= -1;
                }
                
                // Check collision with other balls
                for (let otherBall of balls) {
                    if (ball === otherBall) continue;
                    
                    const dx = otherBall.x - ball.x;
                    const dy = otherBall.y - ball.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    
                    if (distance < ballRadius * 2) {
                        // Simple collision response
                        const angle = Math.atan2(dy, dx);
                        const targetX = ball.x - Math.cos(angle) * ballRadius * 2;
                        const targetY = ball.y - Math.sin(angle) * ballRadius * 2;
                        
                        const ax = (targetX - otherBall.x) * 0.1;
                        const ay = (targetY - otherBall.y) * 0.1;
                        
                        ball.dx -= ax;
                        ball.dy -= ay;
                        otherBall.dx += ax;
                        otherBall.dy += ay;
                    }
                }
            }
        }
        
        function drawBalls() {
            for (let ball of balls) {
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);
                ctx.fillStyle = ball.color;
                ctx.fill();
                ctx.closePath();
            }
        }
        
        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // Update hexagon rotation
            hexagonAngle += 0.005;
            
            // Draw hexagon
            drawHexagon(hexagonRadius, hexagonAngle);
            
            // Update and draw balls
            updateBalls();
            drawBalls();
            
            requestAnimationFrame(animate);
        }
        
        // Handle window resize
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            centerX = canvas.width / 2;
            centerY = canvas.height / 2;
            hexagonRadius = Math.min(canvas.width, canvas.height) * 0.4;
        });
        
        animate();
    </script>
</body>
</html>
```

This code creates:

1. A black background canvas
2. A white hexagon that rotates slowly
3. 10 colorful balls that bounce around inside the hexagon
4. Collision detection between balls and the hexagon walls
5. Simple collision response between balls

The animation uses requestAnimationFrame for smooth rendering. The hexagon rotates continuously while the balls bounce around, changing direction when they hit the hexagon walls or other balls.

You can adjust parameters like:
- Number of balls (ballCount)
- Ball size (ballRadius)
- Hexagon size (hexagonRadius multiplier)
- Rotation speed (hexagonAngle increment)
- Ball speed (dx/dy values)
Meta

Llama 4 Maverick

最终回答
```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Bouncing Balls in Spinning Hexagon</title>
  <style>
    /* Add some basic styling to our canvas */
    canvas {
      border: 1px solid black;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="600" height="600"></canvas>
  <script>
    // Get the canvas element
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    // Define some constants
    const NUM_BALLS = 10;
    const HEXAGON_SIZE = 200;
    const BALL_RADIUS = 10;

    // Define the hexagon's center and rotation angle
    let centerX = canvas.width / 2;
    let centerY = canvas.height / 2;
    let angle = 0;

    // Define the balls' initial positions and velocities
    let balls = [];
    for (let i = 0; i < NUM_BALLS; i++) {
      balls.push({
        x: centerX + Math.random() * HEXAGON_SIZE - HEXAGON_SIZE / 2,
        y: centerY + Math.random() * HEXAGON_SIZE - HEXAGON_SIZE / 2,
        vx: Math.random() * 4 - 2,
        vy: Math.random() * 4 - 2,
      });
    }

    // Main animation loop
    function animate() {
      // Clear the canvas
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw the spinning hexagon
      ctx.save();
      ctx.translate(centerX, centerY);
      ctx.rotate(angle);
      ctx.beginPath();
      for (let i = 0; i < 6; i++) {
        let a = i * Math.PI / 3;
        let x = HEXAGON_SIZE / 2 * Math.cos(a);
        let y = HEXAGON_SIZE / 2 * Math.sin(a);
        ctx.lineTo(x, y);
      }
      ctx.closePath();
      ctx.stroke();
      ctx.restore();

      // Update and draw the balls
      for (let ball of balls) {
        // Update the ball's position
        ball.x += ball.vx;
        ball.y += ball.vy;

        // Bounce off the hexagon's edges
        let dx = ball.x - centerX;
        let dy = ball.y - centerY;
        let dist = Math.sqrt(dx * dx + dy * dy);
        let angle = Math.atan2(dy, dx);
        if (dist > HEXAGON_SIZE / 2 - BALL_RADIUS) {
          // Normalize the ball's position to be on the hexagon's edge
          ball.x = centerX + (HEXAGON_SIZE / 2 - BALL_RADIUS) * Math.cos(angle);
          ball.y = centerY + (HEXAGON_SIZE / 2 - BALL_RADIUS) * Math.sin(angle);

          // Bounce the ball
          let normalX = Math.cos(angle);
          let normalY = Math.sin(angle);
          let dotProduct = ball.vx * normalX + ball.vy * normalY;
          ball.vx -= 2 * dotProduct * normalX;
          ball.vy -= 2 * dotProduct * normalY;
        }

        // Draw the ball
        ctx.beginPath();
        ctx.arc(ball.x, ball.y, BALL_RADIUS, 0, 2 * Math.PI);
        ctx.fill();
      }

      // Update the hexagon's rotation angle
      angle += 0.01;

      // Request the next frame
      requestAnimationFrame(animate);
    }

    // Start the animation
    animate();
  </script>
</body>
</html>
```

This code creates a canvas element and gets a 2D drawing context. It defines some constants for the number of balls, the size of the hexagon, and the radius of the balls. The `animate` function is called repeatedly using `requestAnimationFrame`, and it updates the positions of the balls, draws the spinning hexagon, and draws the balls. The balls bounce off the edges of the hexagon.
Meta

Llama 3.3 Instruct 70B

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        #canvas {
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <script>
        // Get the canvas element
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');

        // Set the canvas dimensions
        canvas.width = 600;
        canvas.height = 600;

        // Define the hexagon properties
        const hexagon = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            radius: 200,
            rotation: 0,
            rotationSpeed: 2
        };

        // Define the ball properties
        const balls = [];
        for (let i = 0; i < 10; i++) {
            balls.push({
                x: Math.random() * canvas.width,
                y: Math.random() * canvas.height,
                radius: 10,
                velocityX: Math.random() * 5 - 2.5,
                velocityY: Math.random() * 5 - 2.5,
                color: `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`
            });
        }

        // Main animation loop
        function animate() {
            // Clear the canvas
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Draw the spinning hexagon
            ctx.save();
            ctx.translate(hexagon.x, hexagon.y);
            ctx.rotate(hexagon.rotation * Math.PI / 180);
            ctx.beginPath();
            for (let i = 0; i < 6; i++) {
                const angle = i * Math.PI / 3;
                ctx.lineTo(hexagon.radius * Math.cos(angle), hexagon.radius * Math.sin(angle));
            }
            ctx.closePath();
            ctx.strokeStyle = 'black';
            ctx.stroke();
            ctx.restore();

            // Update and draw the balls
            for (let i = 0; i < balls.length; i++) {
                const ball = balls[i];

                // Update ball position
                ball.x += ball.velocityX;
                ball.y += ball.velocityY;

                // Bounce off the edges
                if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
                    ball.velocityX *= -1;
                }
                if (ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height) {
                    ball.velocityY *= -1;
                }

                // Check collision with the hexagon
                const distanceToCenter = Math.sqrt((ball.x - hexagon.x) ** 2 + (ball.y - hexagon.y) ** 2);
                if (distanceToCenter < hexagon.radius) {
                    // Calculate the normal vector of the hexagon at the collision point
                    const angleToBall = Math.atan2(ball.y - hexagon.y, ball.x - hexagon.x);
                    const normalX = Math.cos(angleToBall);
                    const normalY = Math.sin(angleToBall);

                    // Reflect the ball's velocity over the normal vector
                    const dotProduct = ball.velocityX * normalX + ball.velocityY * normalY;
                    ball.velocityX = ball.velocityX - 2 * dotProduct * normalX;
                    ball.velocityY = ball.velocityY - 2 * dotProduct * normalY;
                }

                // Draw the ball
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);
                ctx.fillStyle = ball.color;
                ctx.fill();
            }

            // Update the hexagon rotation
            hexagon.rotation += hexagon.rotationSpeed;

            // Request the next animation frame
            requestAnimationFrame(animate);
        }

        // Start the animation
        animate();
    </script>
</body>
</html>
```
SpaceXAI

Grok 3 mini Reasoning (High)

最终回答
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bouncing Balls in Spinning Hexagon</title>
    <style>
        canvas {
            border: 1px solid black;
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    <canvas id="myCanvas" width="500" height="500"></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');
        
        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const radius = 200;  // Radius for the circular boundary and hexagon size
        const numBalls = 10;
        const ballRadius = 10;
        const balls = [];
        
        // Initialize balls with random positions and velocities
        for (let i = 0; i < numBalls; i++) {
            balls.push({
                x: centerX + (Math.random() - 0.5) * radius * 0.8,
                y: centerY + (Math.random() - 0.5) * radius * 0.8,
                vx: (Math.random() - 0.5) * 5,
                vy: (Math.random() - 0.5) * 5
            });
        }
        
        let angle = 0;  // Rotation angle for the hexagon
        
        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // Draw the spinning hexagon
            ctx.save();
            ctx.translate(centerX, centerY);
            ctx.rotate(angle);
            ctx.beginPath();
            for (let i = 0; i < 6; i++) {
                let hexagonAngle = i * Math.PI / 3;
                let hx = radius * Math.cos(hexagonAngle);
                let hy = radius * Math.sin(hexagonAngle);
                if (i === 0) {
                    ctx.moveTo(hx, hy);
                } else {
                    ctx.lineTo(hx, hy);
                }
            }
            ctx.closePath();
            ctx.strokeStyle = 'blue';
            ctx.lineWidth = 2;
            ctx.stroke();
            ctx.restore();
            
            // Update and draw balls
            balls.forEach(ball => {
                ball.x += ball.vx;
                ball.y += ball.vy;
                
                // Check collision with circular boundary
                let dx = ball.x - centerX;
                let dy = ball.y - centerY;
                let distance = Math.sqrt(dx * dx + dy * dy);
                if (distance + ballRadius > radius) {
                    // Simple bounce: Reverse velocity
                    ball.vx = -ball.vx;
                    ball.vy = -ball.vy;
                    // Adjust position to prevent sticking
                    let bounceAngle = Math.atan2(dy, dx);
                    ball.x = centerX + (radius - ballRadius) * Math.cos(bounceAngle);
                    ball.y = centerY + (radius - ballRadius) * Math.sin(bounceAngle);
                }
                
                // Draw the ball
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);
                ctx.fillStyle = 'red';
                ctx.fill();
            });
            
            angle += 0.01;  // Increment rotation angle
            requestAnimationFrame(animate);
        }
        
        animate();
    </script>
</body>
</html>
```