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 Physics Playground</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        user-select: none;
    }
    
    .container {
        position: relative;
        width: 80vw;
        max-width: 900px;
        height: 70vh;
        max-height: 600px;
        background: rgba(255, 255, 255, 0.95);
        border-radius: 20px;
        box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
        overflow: hidden;
        transition: transform 0.3s ease;
    }
    
    .container.spinning {
        animation: spin 2s ease-in-out;
    }
    
    @keyframes spin {
        0% { transform: rotate(0deg); }
        25% { transform: rotate(90deg) scale(1.05); }
        50% { transform: rotate(180deg) scale(1.1); }
        75% { transform: rotate(270deg) scale(1.05); }
        100% { transform: rotate(360deg); }
    }
    
    .fruit {
        position: absolute;
        font-size: 40px;
        cursor: grab;
        transition: transform 0.1s ease;
        z-index: 10;
    }
    
    .fruit:active {
        cursor: grabbing;
        transform: scale(1.2);
        z-index: 100;
    }
    
    .fruit.dragging {
        z-index: 1000;
        filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.3));
    }
    
    .controls {
        margin-top: 30px;
        display: flex;
        gap: 20px;
    }
    
    .btn {
        padding: 15px 40px;
        font-size: 18px;
        font-weight: 600;
        color: white;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border: none;
        border-radius: 50px;
        cursor: pointer;
        transition: all 0.3s ease;
        box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
    }
    
    .btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 15px 30px rgba(102, 126, 234, 0.5);
    }
    
    .btn:active {
        transform: translateY(0);
    }
    
    .btn.reset {
        background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
        box-shadow: 0 10px 20px rgba(245, 87, 108, 0.4);
    }
    
    .btn.reset:hover {
        box-shadow: 0 15px 30px rgba(245, 87, 108, 0.5);
    }
    
    .info {
        position: absolute;
        top: 20px;
        left: 20px;
        color: #666;
        font-size: 14px;
        z-index: 100;
    }
</style>
</head> <body> <div class="info">Drag and throw the fruits!</div> <div class="container" id="container"></div> <div class="controls"> <button class="btn" id="mixBtn">🌀 Mix</button> <button class="btn reset" id="resetBtn">🔄 Reset</button> </div>
<script>
    const fruitEmojis = ['🍎', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍈', '🍒', 
                        '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🍆', '🥑', '🥦', '🥬',
                        '🥒', '🌶️', '🫑', '🌽', '🥕', '🫒', '🧄', '🧅', '🍄', '🥜',
                        '🌰', '🍞', '🥐', '🥖', '🫓', '🥨', '🥯', '🥞', '🧇', '🧀',
                        '🍖', '🍗', '🥩', '🥓', '🍔', '🍟', '🍕', '🌭', '🥪', '🌮'];
    
    class Fruit {
        constructor(x, y, emoji) {
            this.x = x;
            this.y = y;
            this.vx = (Math.random() - 0.5) * 2;
            this.vy = 0;
            this.emoji = emoji;
            this.radius = 20;
            this.mass = 1;
            this.element = null;
            this.isDragging = false;
            this.dragOffsetX = 0;
            this.dragOffsetY = 0;
            this.lastMouseX = 0;
            this.lastMouseY = 0;
            this.mouseVelocityX = 0;
            this.mouseVelocityY = 0;
        }
        
        createElement() {
            const div = document.createElement('div');
            div.className = 'fruit';
            div.textContent = this.emoji;
            div.style.left = this.x + 'px';
            div.style.top = this.y + 'px';
            this.element = div;
            return div;
        }
        
        update(gravity, damping, bounds) {
            if (!this.isDragging) {
                // Apply gravity
                this.vy += gravity;
                
                // Apply damping
                this.vx *= damping;
                this.vy *= damping;
                
                // Update position
                this.x += this.vx;
                this.y += this.vy;
                
                // Bounce off walls
                if (this.x - this.radius < 0) {
                    this.x = this.radius;
                    this.vx = Math.abs(this.vx) * 0.8;
                }
                if (this.x + this.radius > bounds.width) {
                    this.x = bounds.width - this.radius;
                    this.vx = -Math.abs(this.vx) * 0.8;
                }
                if (this.y + this.radius > bounds.height) {
                    this.y = bounds.height - this.radius;
                    this.vy = -Math.abs(this.vy) * 0.7;
                    
                    // Stop tiny bounces
                    if (Math.abs(this.vy) < 0.5) {
                        this.vy = 0;
                    }
                }
                if (this.y - this.radius < 0) {
                    this.y = this.radius;
                    this.vy = Math.abs(this.vy) * 0.8;
                }
            }
            
            // Update DOM element
            if (this.element) {
                this.element.style.left = (this.x - this.radius) + 'px';
                this.element.style.top = (this.y - this.radius) + 'px';
            }
        }
        
        checkCollision(other) {
            const dx = other.x - this.x;
            const dy = other.y - this.y;
            const distance = Math.sqrt(dx * dx + dy * dy);
            const minDistance = this.radius + other.radius;
            
            if (distance < minDistance) {
                // Collision detected
                const angle = Math.atan2(dy, dx);
                const targetX = this.x + Math.cos(angle) * minDistance;
                const targetY = this.y + Math.sin(angle) * minDistance;
                const ax = (targetX - other.x) * 0.05;
                const ay = (targetY - other.y) * 0.05;
                
                // Apply forces
                if (!this.isDragging) {
                    this.vx -= ax;
                    this.vy -= ay;
                }
                if (!other.isDragging) {
                    other.vx += ax;
                    other.vy += ay;
                }
                
                // Separate overlapping fruits
                const overlap = minDistance - distance;
                const separationX = (dx / distance) * overlap * 0.5;
                const separationY = (dy / distance) * overlap * 0.5;
                
                if (!this.isDragging) {
                    this.x -= separationX;
                    this.y -= separationY;
                }
                if (!other.isDragging) {
                    other.x += separationX;
                    other.y += separationY;
                }
            }
        }
        
        startDrag(mouseX, mouseY) {
            this.isDragging = true;
            this.dragOffsetX = mouseX - this.x;
            this.dragOffsetY = mouseY - this.y;
            this.lastMouseX = mouseX;
            this.lastMouseY = mouseY;
            this.element.classList.add('dragging');
        }
        
        drag(mouseX, mouseY) {
            if (this.isDragging) {
                // Calculate mouse velocity
                this.mouseVelocityX = mouseX - this.lastMouseX;
                this.mouseVelocityY = mouseY - this.lastMouseY;
                
                // Update position
                this.x = mouseX - this.dragOffsetX;
                this.y = mouseY - this.dragOffsetY;
                
                // Store last mouse position
                this.lastMouseX = mouseX;
                this.lastMouseY = mouseY;
            }
        }
        
        endDrag() {
            if (this.isDragging) {
                this.isDragging = false;
                this.vx = this.mouseVelocityX * 0.5;
                this.vy = this.mouseVelocityY * 0.5;
                this.element.classList.remove('dragging');
            }
        }
    }
    
    class PhysicsSimulation {
        constructor(container) {
            this.container = container;
            this.fruits = [];
            this.gravity = 0.3;
            this.damping = 0.99;
            this.bounds = { width: 0, height: 0 };
            this.animationId = null;
            this.draggedFruit = null;
            this.isSpinning = false;
            
            this.init();
        }
        
        init() {
            this.updateBounds();
            this.createFruits();
            this.setupEventListeners();
            this.animate();
        }
        
        updateBounds() {
            const rect = this.container.getBoundingClientRect();
            this.bounds.width = rect.width;
            this.bounds.height = rect.height;
        }
        
        createFruits() {
            this.container.innerHTML = '';
            this.fruits = [];
            
            for (let i = 0; i < 50; i++) {
                const x = Math.random() * (this.bounds.width - 40) + 20;
                const y = Math.random() * (this.bounds.height / 2);
                const emoji = fruitEmojis[Math.floor(Math.random() * fruitEmojis.length)];
                
                const fruit = new Fruit(x, y, emoji);
                const element = fruit.createElement();
                this.container.appendChild(element);
                this.fruits.push(fruit);
            }
        }
        
        setupEventListeners() {
            // Mouse events
            this.container.addEventListener('mousedown', (e) => this.handleMouseDown(e));
            document.addEventListener('mousemove', (e) => this.handleMouseMove(e));
            document.addEventListener('mouseup', () => this.handleMouseUp());
            
            // Touch events
            this.container.addEventListener('touchstart', (e) => this.handleTouchStart(e));
            document.addEventListener('touchmove', (e) => this.handleTouchMove(e));
            document.addEventListener('touchend', () => this.handleTouchEnd());
            
            // Window resize
            window.addEventListener('resize', () => this.updateBounds());
        }
        
        handleMouseDown(e) {
            const rect = this.container.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            
            for (let fruit of this.fruits) {
                const dx = mouseX - fruit.x;
                const dy = mouseY - fruit.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < fruit.radius) {
                    this.draggedFruit = fruit;
                    fruit.startDrag(mouseX, mouseY);
                    break;
                }
            }
        }
        
        handleMouseMove(e) {
            if (this.draggedFruit) {
                const rect = this.container.getBoundingClientRect();
                const mouseX = e.clientX - rect.left;
                const mouseY = e.clientY - rect.top;
                this.draggedFruit.drag(mouseX, mouseY);
            }
        }
        
        handleMouseUp() {
            if (this.draggedFruit) {
                this.draggedFruit.endDrag();
                this.draggedFruit = null;
            }
        }
        
        handleTouchStart(e) {
            e.preventDefault();
            const rect = this.container.getBoundingClientRect();
            const touch = e.touches[0];
            const touchX = touch.clientX - rect.left;
            const touchY = touch.clientY - rect.top;
            
            for (let fruit of this.fruits) {
                const dx = touchX - fruit.x;
                const dy = touchY - fruit.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < fruit.radius) {
                    this.draggedFruit = fruit;
                    fruit.startDrag(touchX, touchY);
                    break;
                }
            }
        }
        
        handleTouchMove(e) {
            e.preventDefault();
            if (this.draggedFruit) {
                const rect = this.container.getBoundingClientRect();
                const touch = e.touches[0];
                const touchX = touch.clientX - rect.left;
                const touchY = touch.clientY - rect.top;
                this.draggedFruit.drag(touchX, touchY);
            }
        }
        
        handleTouchEnd() {
            if (this.draggedFruit) {
                this.draggedFruit.endDrag();
                this.draggedFruit = null;
            }
        }
        
        animate() {
            // Update physics
            for (let fruit of this.fruits) {
                fruit.update(this.gravity, this.damping, this.bounds);
            }
            
            // Check collisions
            for (let i = 0; i < this.fruits.length; i++) {
                for (let j = i + 1; j < this.fruits.length; j++) {
                    this.fruits[i].checkCollision(this.fruits[j]);
                }
            }
            
            this.animationId = requestAnimationFrame(() => this.animate());
        }
        
        mix() {
            if (this.isSpinning) return;
            
            this.isSpinning = true;
            this.container.classList.add('spinning');
            
            // Add random forces to all fruits
            this.fruits.forEach(fruit => {
                fruit.vx = (Math.random() - 0.5) * 20;
                fruit.vy = (Math.random() - 0.5) * 20;
            });
            
            setTimeout(() => {
                this.container.classList.remove('spinning');
                this.isSpinning = false;
            }, 2000);
        }
        
        reset() {
            this.createFruits();
        }
        
        destroy() {
            if (this.animationId) {
                cancelAnimationFrame(this.animationId);
            }
        }
    }
    
    // Initialize simulation
    const container = document.getElementById('container');
    const simulation = new PhysicsSimulation(container);
    
    // Button controls
    document.getElementById('mixBtn').addEventListener('click', () => {
        simulation.mix();
    });
    
    document.getElementById('resetBtn').addEventListener('click', () => {
        simulation.reset();
    });
</script>
</body> </html>*
Updated files
v1