JIT
Grid - Untitled
Create a box on the screen filled with 50 different, random fruit emojis. The emojis must have physics (matter.js style logic, but written from scratch): they fall, bounce off each other, and stack up. The user can pick them up and throw them with the mouse. Add a 'Mix' button that spins the container like a washing machine.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fruit Emoji Physics</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: Arial, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        overflow: hidden;
    }

    .container {
        position: relative;
        width: 90vw;
        height: 70vh;
        max-width: 1200px;
        max-height: 800px;
        background: rgba(255, 255, 255, 0.1);
        border-radius: 20px;
        border: 3px solid rgba(255, 255, 255, 0.3);
        backdrop-filter: blur(10px);
        overflow: hidden;
        box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
    }

    .controls {
        margin-top: 2rem;
        display: flex;
        gap: 1rem;
    }

    button {
        padding: 1rem 2rem;
        font-size: 1.2rem;
        background: linear-gradient(45deg, #ff6b6b, #ee5a24);
        color: white;
        border: none;
        border-radius: 50px;
        cursor: pointer;
        transition: all 0.3s ease;
        box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
    }

    button:hover {
        transform: translateY(-2px);
        box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
    }

    button:active {
        transform: translateY(0);
    }

    .fruit {
        position: absolute;
        font-size: 2rem;
        user-select: none;
        cursor: grab;
        transition: transform 0.1s ease;
        text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
    }

    .fruit:active {
        cursor: grabbing;
    }

    .stats {
        color: white;
        margin-top: 1rem;
        font-size: 1.1rem;
        text-align: center;
    }
</style>
</head> <body> <div class="container" id="gameContainer"></div> <div class="controls"> <button id="mixButton">Mix Fruits!</button> <button id="resetButton">Reset</button> </div> <div class="stats" id="stats">Fruits: 50 | Grabbed: 0</div>
<script>
    class FruitPhysics {
        constructor() {
            this.container = document.getElementById('gameContainer');
            this.fruits = [];
            this.grabbedFruit = null;
            this.grabOffset = { x: 0, y: 0 };
            this.isMixing = false;
            this.mixAngle = 0;
            this.fruitsGrabbed = 0;
            
            this.fruitEmojis = [
                '🍎', '🍌', '🍇', '🍓', '🍊', '🍋', '🍉', '🍑', '🍍', '🥭',
                '🍒', '🍐', '🥝', '🍅', '🥥', '🥑', '🍈', '🫐', '🍏', '🥭',
                '🍎', '🍌', '🍇', '🍓', '🍊', '🍋', '🍉', '🍑', '🍍', '🥭',
                '🍒', '🍐', '🥝', '🍅', '🥥', '🥑', '🍈', '🫐', '🍏', '🥭',
                '🍎', '🍌', '🍇', '🍓', '🍊', '🍋', '🍉', '🍑', '🍍', '🥭'
            ];

            this.init();
            this.createFruits();
            this.animate();
            this.setupEventListeners();
        }

        init() {
            const rect = this.container.getBoundingClientRect();
            this.bounds = {
                left: 10,
                right: rect.width - 50,
                top: 10,
                bottom: rect.height - 50
            };
        }

        createFruits() {
            for (let i = 0; i < 50; i++) {
                const fruit = document.createElement('div');
                fruit.className = 'fruit';
                fruit.textContent = this.fruitEmojis[i];
                fruit.style.left = Math.random() * (this.bounds.right - 50) + 'px';
                fruit.style.top = Math.random() * 200 + 'px';
                
                this.container.appendChild(fruit);
                
                this.fruits.push({
                    element: fruit,
                    x: parseFloat(fruit.style.left),
                    y: parseFloat(fruit.style.top),
                    vx: (Math.random() - 0.5) * 4,
                    vy: Math.random() * 2 + 1,
                    radius: 25,
                    mass: 1,
                    isGrabbed: false
                });
            }
        }

        updateFruit(fruit, deltaTime) {
            if (fruit.isGrabbed || this.isMixing) return;

            // Apply gravity
            fruit.vy += 0.2 * deltaTime;

            // Update position
            fruit.x += fruit.vx * deltaTime;
            fruit.y += fruit.vy * deltaTime;

            // Boundary collision
            if (fruit.x < this.bounds.left) {
                fruit.x = this.bounds.left;
                fruit.vx *= -0.8;
            } else if (fruit.x > this.bounds.right) {
                fruit.x = this.bounds.right;
                fruit.vx *= -0.8;
            }

            if (fruit.y < this.bounds.top) {
                fruit.y = this.bounds.top;
                fruit.vy *= -0.8;
            } else if (fruit.y > this.bounds.bottom) {
                fruit.y = this.bounds.bottom;
                fruit.vy *= -0.8;
                fruit.vx *= 0.98; // Friction
            }

            // Apply mixing rotation
            if (this.isMixing) {
                const centerX = this.container.clientWidth / 2;
                const centerY = this.container.clientHeight / 2;
                
                const dx = fruit.x - centerX;
                const dy = fruit.y - centerY;
                const distance = Math.sqrt(dx * dx + dy * dy);
                const angle = Math.atan2(dy, dx) + 0.05;
                
                fruit.x = centerX + Math.cos(angle) * distance;
                fruit.y = centerY + Math.sin(angle) * distance;
                
                // Add centrifugal force
                fruit.vx += dx * 0.001;
                fruit.vy += dy * 0.001;
            }

            // Update element position
            fruit.element.style.left = fruit.x + 'px';
            fruit.element.style.top = fruit.y + 'px';
        }

        checkCollisions() {
            for (let i = 0; i < this.fruits.length; i++) {
                for (let j = i + 1; j < this.fruits.length; j++) {
                    const fruit1 = this.fruits[i];
                    const fruit2 = this.fruits[j];
                    
                    if (fruit1.isGrabbed || fruit2.isGrabbed) continue;

                    const dx = fruit2.x - fruit1.x;
                    const dy = fruit2.y - fruit1.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    const minDistance = fruit1.radius + fruit2.radius;

                    if (distance < minDistance) {
                        // Collision response
                        const angle = Math.atan2(dy, dx);
                        const overlap = minDistance - distance;
                        
                        // Separate fruits
                        const moveX = (overlap * 0.5) * Math.cos(angle);
                        const moveY = (overlap * 0.5) * Math.sin(angle);
                        
                        fruit1.x -= moveX;
                        fruit1.y -= moveY;
                        fruit2.x += moveX;
                        fruit2.y += moveY;

                        // Bounce
                        const speed1 = Math.sqrt(fruit1.vx * fruit1.vx + fruit1.vy * fruit1.vy);
                        const speed2 = Math.sqrt(fruit2.vx * fruit2.vx + fruit2.vy * fruit2.vy);
                        
                        fruit1.vx = -fruit1.vx * 0.8 + (Math.random() - 0.5) * 2;
                        fruit1.vy = -fruit1.vy * 0.8 + (Math.random() - 0.5) * 2;
                        fruit2.vx = -fruit2.vx * 0.8 + (Math.random() - 0.5) * 2;
                        fruit2.vy = -fruit2.vy * 0.8 + (Math.random() - 0.5) * 2;
                    }
                }
            }
        }

        grabFruit(x, y) {
            for (let i = this.fruits.length - 1; i >= 0; i--) {
                const fruit = this.fruits[i];
                const dx = x - fruit.x;
                const dy = y - fruit.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < fruit.radius) {
                    this.grabbedFruit = fruit;
                    fruit.isGrabbed = true;
                    this.grabOffset.x = dx;
                    this.grabOffset.y = dy;
                    fruit.element.style.transform = 'scale(1.2)';
                    fruit.element.style.zIndex = '1000';
                    this.fruitsGrabbed++;
                    this.updateStats();
                    break;
                }
            }
        }

        moveGrabbedFruit(x, y) {
            if (this.grabbedFruit) {
                this.grabbedFruit.x = x - this.grabOffset.x;
                this.grabbedFruit.y = y - this.grabOffset.y;
                
                this.grabbedFruit.element.style.left = this.grabbedFruit.x + 'px';
                this.grabbedFruit.element.style.top = this.grabbedFruit.y + 'px';
            }
        }

        releaseFruit(x, y) {
            if (this.grabbedFruit) {
                this.grabbedFruit.isGrabbed = false;
                this.grabbedFruit.element.style.transform = 'scale(1)';
                this.grabbedFruit.element.style.zIndex = '1';
                
                // Add throw velocity based on mouse movement
                const throwStrength = 0.5;
                this.grabbedFruit.vx = (x - this.grabbedFruit.x) * throwStrength;
                this.grabbedFruit.vy = (y - this.grabbedFruit.y) * throwStrength;
                
                this.grabbedFruit = null;
            }
        }

        mixFruits() {
            this.isMixing = true;
            this.container.style.transition = 'transform 0.5s ease';
            this.container.style.transform = 'rotate(360deg)';
            
            setTimeout(() => {
                this.isMixing = false;
                this.container.style.transition = 'transform 0.3s ease';
                this.container.style.transform = 'rotate(0deg)';
            }, 3000);
        }

        resetFruits() {
            this.fruits.forEach(fruit => {
                fruit.x = Math.random() * (this.bounds.right - 50);
                fruit.y = Math.random() * 200;
                fruit.vx = (Math.random() - 0.5) * 4;
                fruit.vy = Math.random() * 2 + 1;
                fruit.isGrabbed = false;
                
                fruit.element.style.left = fruit.x + 'px';
                fruit.element.style.top = fruit.y + 'px';
                fruit.element.style.transform = 'scale(1)';
                fruit.element.style.zIndex = '1';
            });
            
            this.grabbedFruit = null;
            this.fruitsGrabbed = 0;
            this.updateStats();
        }

        updateStats() {
            document.getElementById('stats').textContent = 
                `Fruits: 50 | Grabbed: ${this.fruitsGrabbed}`;
        }

        setupEventListeners() {
            this.container.addEventListener('mousedown', (e) => {
                const rect = this.container.getBoundingClientRect();
                this.grabFruit(e.clientX - rect.left, e.clientY - rect.top);
            });

            this.container.addEventListener('mousemove', (e) => {
                if (this.grabbedFruit) {
                    const rect = this.container.getBoundingClientRect();
                    this.moveGrabbedFruit(e.clientX - rect.left, e.clientY - rect.top);
                }
            });

            this.container.addEventListener('mouseup', (e) => {
                if (this.grabbedFruit) {
                    const rect = this.container.getBoundingClientRect();
                    this.releaseFruit(e.clientX - rect.left, e.clientY - rect.top);
                }
            });

            // Touch events for mobile
            this.container.addEventListener('touchstart', (e) => {
                e.preventDefault();
                const rect = this.container.getBoundingClientRect();
                const touch = e.touches[0];
                this.grabFruit(touch.clientX - rect.left, touch.clientY - rect.top);
            });

            this.container.addEventListener('touchmove', (e) => {
                e.preventDefault();
                if (this.grabbedFruit) {
                    const rect = this.container.getBoundingClientRect();
                    const touch = e.touches[0];
                    this.moveGrabbedFruit(touch.clientX - rect.left, touch.clientY - rect.top);
                }
            });

            this.container.addEventListener('touchend', (e) => {
                if (this.grabbedFruit) {
                    const rect = this.container.getBoundingClientRect();
                    const touch = e.changedTouches[0];
                    this.releaseFruit(touch.clientX - rect.left, touch.clientY - rect.top);
                }
            });

            document.getElementById('mixButton').addEventListener('click', () => {
                this.mixFruits();
            });

            document.getElementById('resetButton').addEventListener('click', () => {
                this.resetFruits();
            });

            window.addEventListener('resize', () => {
                this.init();
            });
        }

        animate() {
            let lastTime = 0;
            
            const update = (currentTime) => {
                const deltaTime = Math.min((currentTime - lastTime) / 16, 2);
                lastTime = currentTime;

                this.fruits.forEach(fruit => {
                    this.updateFruit(fruit, deltaTime);
                });
                
                this.checkCollisions();
                
                requestAnimationFrame(update);
            };
            
            requestAnimationFrame(update);
        }
    }

    // Initialize the physics simulation when the page loads
    window.addEventListener('load', () => {
        new FruitPhysics();
    });
</script>
</body> </html>*
Updated files
v1