JIT
Grid - Untitled
Write a script for the classic "DVD Logo" bounce animation. A rectangle must move diagonally, bounce off the viewport edges, and change its color to a random value upon every collision.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DVD Logo Bounce</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
        width: 100vw;
        height: 100vh;
        overflow: hidden;
        background: #000;
        position: relative;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
    }

    #dvd-logo {
        position: absolute;
        width: 120px;
        height: 60px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 8px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        font-weight: bold;
        color: white;
        text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        box-shadow: 0 4px 20px rgba(0,0,0,0.5);
        transition: background 0.1s ease;
        user-select: none;
        cursor: default;
    }

    #dvd-logo::before {
        content: '';
        position: absolute;
        inset: -2px;
        background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent);
        border-radius: 8px;
        opacity: 0;
        transition: opacity 0.3s;
    }

    #dvd-logo:hover::before {
        opacity: 1;
    }

    .corner-hit {
        animation: pulse 0.3s ease;
    }

    @keyframes pulse {
        0% { transform: scale(1); }
        50% { transform: scale(1.1); }
        100% { transform: scale(1); }
    }

    .stats {
        position: absolute;
        top: 20px;
        left: 20px;
        color: rgba(255, 255, 255, 0.7);
        font-size: 14px;
        font-family: 'Courier New', monospace;
        background: rgba(0, 0, 0, 0.5);
        padding: 10px 15px;
        border-radius: 5px;
        backdrop-filter: blur(10px);
    }

    .controls {
        position: absolute;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%);
        display: flex;
        gap: 10px;
        background: rgba(0, 0, 0, 0.7);
        padding: 10px 20px;
        border-radius: 25px;
        backdrop-filter: blur(10px);
    }

    button {
        padding: 8px 16px;
        background: rgba(255, 255, 255, 0.1);
        color: white;
        border: 1px solid rgba(255, 255, 255, 0.3);
        border-radius: 5px;
        cursor: pointer;
        transition: all 0.3s;
        font-size: 14px;
    }

    button:hover {
        background: rgba(255, 255, 255, 0.2);
        transform: translateY(-2px);
    }

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

    .speed-control {
        display: flex;
        align-items: center;
        gap: 10px;
        color: white;
        font-size: 14px;
    }

    input[type="range"] {
        width: 100px;
        height: 4px;
        background: rgba(255, 255, 255, 0.3);
        outline: none;
        cursor: pointer;
    }

    input[type="range"]::-webkit-slider-thumb {
        -webkit-appearance: none;
        appearance: none;
        width: 16px;
        height: 16px;
        background: white;
        cursor: pointer;
        border-radius: 50%;
    }

    input[type="range"]::-moz-range-thumb {
        width: 16px;
        height: 16px;
        background: white;
        cursor: pointer;
        border-radius: 50%;
        border: none;
    }
</style>
</head> <body> <div id="dvd-logo">DVD</div>
<div class="stats">
    <div>Bounces: <span id="bounce-count">0</span></div>
    <div>Speed: <span id="speed-display">3</span> px/frame</div>
</div>

<div class="controls">
    <button id="pause-btn">Pause</button>
    <button id="reset-btn">Reset</button>
    <div class="speed-control">
        <label>Speed:</label>
        <input type="range" id="speed-slider" min="1" max="10" value="3">
    </div>
</div>

<script>
    const logo = document.getElementById('dvd-logo');
    const bounceCountEl = document.getElementById('bounce-count');
    const speedDisplay = document.getElementById('speed-display');
    const pauseBtn = document.getElementById('pause-btn');
    const resetBtn = document.getElementById('reset-btn');
    const speedSlider = document.getElementById('speed-slider');

    let x = Math.random() * (window.innerWidth - 120);
    let y = Math.random() * (window.innerHeight - 60);
    let dx = 3;
    let dy = 3;
    let bounceCount = 0;
    let isPaused = false;
    let animationId = null;

    function getRandomColor() {
        const colors = [
            'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
            'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
            'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
            'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
            'linear-gradient(135deg, #fa709a 0%, #fee140 100%)',
            'linear-gradient(135deg, #30cfd0 0%, #330867 100%)',
            'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)',
            'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)',
            'linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%)',
            'linear-gradient(135deg, #fdcbf1 0%, #e6dee9 100%)',
            'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',
            'linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)',
            'linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)',
            'linear-gradient(135deg, #fddb92 0%, #d1fdff 100%)',
            'linear-gradient(135deg, #9890e3 0%, #b1f4cf 100%)'
        ];
        return colors[Math.floor(Math.random() * colors.length)];
    }

    function animate() {
        if (isPaused) return;

        const logoWidth = 120;
        const logoHeight = 60;
        const maxX = window.innerWidth - logoWidth;
        const maxY = window.innerHeight - logoHeight;

        x += dx;
        y += dy;

        let bounced = false;

        if (x <= 0 || x >= maxX) {
            dx = -dx;
            x = x <= 0 ? 0 : maxX;
            bounced = true;
        }

        if (y <= 0 || y >= maxY) {
            dy = -dy;
            y = y <= 0 ? 0 : maxY;
            bounced = true;
        }

        if (bounced) {
            logo.style.background = getRandomColor();
            bounceCount++;
            bounceCountEl.textContent = bounceCount;
            logo.classList.add('corner-hit');
            setTimeout(() => logo.classList.remove('corner-hit'), 300);
        }

        logo.style.left = x + 'px';
        logo.style.top = y + 'px';

        animationId = requestAnimationFrame(animate);
    }

    pauseBtn.addEventListener('click', () => {
        isPaused = !isPaused;
        pauseBtn.textContent = isPaused ? 'Resume' : 'Pause';
        if (!isPaused) animate();
    });

    resetBtn.addEventListener('click', () => {
        x = Math.random() * (window.innerWidth - 120);
        y = Math.random() * (window.innerHeight - 60);
        dx = 3;
        dy = 3;
        bounceCount = 0;
        bounceCountEl.textContent = bounceCount;
        logo.style.background = getRandomColor();
        if (isPaused) {
            isPaused = false;
            pauseBtn.textContent = 'Pause';
            animate();
        }
    });

    speedSlider.addEventListener('input', (e) => {
        const speed = parseInt(e.target.value);
        const ratio = speed / Math.abs(dx);
        dx = Math.sign(dx) * speed;
        dy = Math.sign(dy) * speed;
        speedDisplay.textContent = speed;
    });

    window.addEventListener('resize', () => {
        const maxX = window.innerWidth - 120;
        const maxY = window.innerHeight - 60;
        if (x > maxX) x = maxX;
        if (y > maxY) y = maxY;
    });

    // Start animation
    animate();
</script>
</body> </html>
Updated files
v1