Category: fun

  • puzzle

    <!DOCTYPE html> 
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name='robots' content='noindex, nofollow'/>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="theme-color" content="#FFFFFF">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
    <meta name="format-detection" content="telephone=no"> 
    <link rel="apple-touch-icon" sizes="180x180" href="icon.png">
    <meta name="apple-mobile-web-app-title" content="Cat">
    <link rel="icon" type="image/png" sizes="192x192" href="icon.png">
    <link rel="icon" type="image/png" sizes="512x512" href="icon.png"> 
      
       <title>Cat</title>
        <style>
            :root {
                --tile-size: min(12vh, 25vw);
                --gap: 8px;
            }
    
            * { 
                box-sizing: border-box; 
                touch-action: none; 
                -webkit-user-select: none;
                user-select: none;
            }
    
            body {
                margin: 0;
                padding: 0;
                height: 100dvh;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: space-evenly;
                background-color: #f0f9ff;
                font-family: 'Comic Sans MS', sans-serif;
                overflow: hidden;
            }
    
            .grid {
                display: grid;
                grid-template-columns: repeat(3, var(--tile-size));
                grid-template-rows: repeat(3, var(--tile-size));
                gap: var(--gap);
                padding: var(--gap);
                background: #e2e8f0;
                border-radius: 15px;
                box-shadow: inset 0 4px 10px rgba(0,0,0,0.1);
            }
            .full { width: 80%; }
    
            .tray {
                display: grid;
                grid-template-columns: repeat(3, var(--tile-size));
                grid-template-rows: repeat(3, var(--tile-size));
                gap: var(--gap);
                padding: var(--gap);
                background: rgba(255,255,255,0.5);
                border: 3px dashed #94a3b8;
                border-radius: 15px;
            }
    
            .slot {
                width: var(--tile-size);
                height: var(--tile-size);
                background: #cbd5e1;
                border-radius: 8px;
                position: relative;
            }
    
            .piece {
                width: var(--tile-size);
                height: var(--tile-size);
                background-size: cover;
                background-position: center;
                border-radius: 8px;
                position: absolute;
                cursor: grab;
                z-index: 2;
                transition: transform 0.1s;
                box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            }
    
            .piece.dragging {
                z-index: 100;
                transform: scale(1.1);
                box-shadow: 0 10px 20px rgba(0,0,0,0.2);
                opacity: 0.9;
            }
    
            #win-overlay {
                position: fixed;
                inset: 0;
                background: rgba(255, 255, 255, 0.9);
                display: none;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                z-index: 1000;
            }
    
            .btn {
                padding: 15px 30px;
                background: #0ea5e9;
                color: white;
                border: none;
                border-radius: 50px;
                font-size: 1.2rem;
                font-weight: bold;
                box-shadow: 0 4px 0 #0369a1;
            }
        </style>
    </head>
    <body> 
    
        <div class="grid" id="main-grid">
            <div class="slot" data-index="1"></div>
            <div class="slot" data-index="2"></div>
            <div class="slot" data-index="3"></div>
            <div class="slot" data-index="4"></div>
            <div class="slot" data-index="5"></div>
            <div class="slot" data-index="6"></div>
            <div class="slot" data-index="7"></div>
            <div class="slot" data-index="8"></div>
            <div class="slot" data-index="9"></div>
        </div>
    
        <div class="tray" id="tray">
            <div class="slot"></div><div class="slot"></div><div class="slot"></div>
            <div class="slot"></div><div class="slot"></div><div class="slot"></div>
            <div class="slot"></div><div class="slot"></div><div class="slot"></div>
        </div>
    
        <div id="win-overlay">
            <img class="full" src="full.jpg">
            <h2 style="color: #0369a1; font-size: 2rem;">Meow! You found cat!</h2>
            <button class="btn" onclick="location.reload()">Play Again</button>
        </div>
    
        <script>
            // --- SOUND ENGINE ---
            const AudioContext = window.AudioContext || window.webkitAudioContext;
            const audioCtx = new AudioContext();
    
            const unlockAudio = () => {
                if (audioCtx.state === 'suspended') audioCtx.resume();
                const osc = audioCtx.createOscillator();
                const gain = audioCtx.createGain();
                gain.gain.value = 0; 
                osc.connect(gain);
                gain.connect(audioCtx.destination);
                osc.start(0); osc.stop(0.1);
                window.removeEventListener('pointerdown', unlockAudio);
                window.removeEventListener('touchstart', unlockAudio);
            };
            window.addEventListener('pointerdown', unlockAudio);
            window.addEventListener('touchstart', unlockAudio);
    
            function playTone(freq, type, duration, vol = 0.1) {
                try {
                    const osc = audioCtx.createOscillator();
                    const gain = audioCtx.createGain();
                    osc.type = type;
                    osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
                    gain.gain.setValueAtTime(vol, audioCtx.currentTime);
                    gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);
                    osc.connect(gain);
                    gain.connect(audioCtx.destination);
                    osc.start();
                    osc.stop(audioCtx.currentTime + duration);
                } catch(e) {}
            }
    
            // --- WEB SPEECH FUNCTION ---
            function speakWinMessage() {
                if ('speechSynthesis' in window) {
                    const msg = new SpeechSynthesisUtterance();
                    msg.text = "Meow! You found cat!";
                    msg.rate = 1;
                    msg.pitch = 1.3; // Higher pitch for cat theme
                    window.speechSynthesis.speak(msg);
                }
            }
    
            const SFX = {
                pickup: () => playTone(600, 'sine', 0.1),
                drop: () => playTone(400, 'triangle', 0.15),
                tap: () => playTone(800, 'sine', 0.05, 0.05),
                win: () => {
                    const notes = [523, 659, 783, 1046];
                    notes.forEach((f, i) => setTimeout(() => playTone(f, 'sine', 0.4, 0.05), i * 120));
                }
            };
    
            // --- GAME LOGIC ---
            let draggedElement = null;
            let startX, startY, initialX, initialY;
            const traySlots = document.querySelectorAll('#tray .slot');
            const gridSlots = document.querySelectorAll('#main-grid .slot');
    
            function init() {
                const ids = [1, 2, 3, 4, 5, 6, 7, 8, 9].sort(() => Math.random() - 0.5);
                ids.forEach((id, i) => {
                    const piece = document.createElement('div');
                    piece.className = 'piece';
                    piece.style.backgroundImage = `url('${id}.jpg')`;
                    piece.dataset.id = id;
                    piece.addEventListener('pointerdown', onPointerDown);
                    piece.addEventListener('click', onClickPiece);
                    traySlots[i].appendChild(piece);
                });
            }
    
            function onPointerDown(e) {
                SFX.pickup();
                draggedElement = e.target;
                draggedElement.classList.add('dragging');
                const rect = draggedElement.getBoundingClientRect();
                startX = e.clientX; startY = e.clientY;
                initialX = rect.left; initialY = rect.top;
                draggedElement.style.position = 'fixed';
                draggedElement.style.left = initialX + 'px';
                draggedElement.style.top = initialY + 'px';
                document.addEventListener('pointermove', onPointerMove);
                document.addEventListener('pointerup', onPointerUp);
            }
    
            function onPointerMove(e) {
                if (!draggedElement) return;
                draggedElement.style.left = (initialX + (e.clientX - startX)) + 'px';
                draggedElement.style.top = (initialY + (e.clientY - startY)) + 'px';
            }
    
            function onPointerUp(e) {
                if (!draggedElement) return;
                SFX.drop();
                draggedElement.hidden = true;
                const target = document.elementFromPoint(e.clientX, e.clientY);
                draggedElement.hidden = false;
                const slot = target ? target.closest('.slot') : null;
                if (slot) {
                    if (slot.hasChildNodes()) {
                        const existingPiece = slot.querySelector('.piece');
                        draggedElement.parentElement.appendChild(existingPiece);
                        existingPiece.style.position = 'static';
                    }
                    slot.appendChild(draggedElement);
                }
                draggedElement.style.position = 'static';
                draggedElement.classList.remove('dragging');
                draggedElement = null;
                document.removeEventListener('pointermove', onPointerMove);
                document.removeEventListener('pointerup', onPointerUp);
                checkWin();
            }
    
            function onClickPiece(e) {
                const piece = e.target;
                if (piece.closest('#main-grid')) {
                    SFX.tap();
                    for (let slot of traySlots) {
                        if (!slot.hasChildNodes()) {
                            slot.appendChild(piece);
                            break;
                        }
                    }
                }
            }
    
            function checkWin() {
                let correct = 0;
                gridSlots.forEach((slot, i) => {
                    const piece = slot.querySelector('.piece');
                    if (piece && piece.dataset.id == (i + 1)) correct++;
                });
                if (correct === 9) {
                    SFX.win();
                    document.getElementById('win-overlay').style.display = 'flex';
                    // Trigger Web Speech
                    speakWinMessage();
                }
            }
    
            init();
        </script>
    </body>
    </html>