گروت فراری :root { --size: 130px; } body { margin: 0; padding: 0; background: linear-gradient(135deg, #4a5a25, #6c4b2b); /* سبز لجنی + قهوهای */ color: #fff; font-family: Tahoma, Arial, sans-serif; } .mover-wrap { max-width: 760px; margin: 20px auto; padding: 16px; border-radius: 12px; background: rgba(0, 0, 0, 0.35); overflow: hidden; } h2 { margin-top: 0; font-size: 1.6rem; } .grid { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 16px; position: relative; height: 420px; } .placeholder { border: 2px dashed #cbd5e1; border-radius: 10px; min-height: 160px; display: flex; align-items: center; justify-content: center; position: relative; color: #e2e8f0; overflow: hidden; } .controls { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 16px; justify-content: center; } .controls button { padding: 12px 18px; border-radius: 10px; border: 1px solid #adb5bd; background: #ffffffbb; color: #000; cursor: pointer; font-size: 1rem; min-width: 90px; } .controls button:focus { outline: 3px solid #d0e2ff; outline-offset: 2px; } .stage { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } .groot { position: absolute; width: var(--size); height: var(--size); border-radius: 12px; overflow: hidden; box-shadow: 0 8px 20px rgba(20,30,50,0.3); transition: transform 350ms cubic-bezier(.25,.9,.25,1); transform-origin: center; pointer-events: auto; } .groot img { width: 100%; height: 100%; object-fit: cover; display: block; } @media (max-width:520px){ :root { --size: 100px; } .grid { height: 340px; } .controls button { padding: 14px; font-size: 1.1rem; min-width: 100px; } h2 { font-size: 1.4rem; } p { font-size: 0.95rem; } } 🌱 گروت فراری روی دکمهها بزن یا سعی کن گروت رو لمس کنی — ولی نمیتونی! 😄 جای خالی ۱ جای خالی ۲ جای خالی ۳ جای خالی ۴ دکمه ۱ دکمه ۲ نیروی جنگل گروت عزیز (function(){ const grid = document.getElementById('grid'); const placeholders = Array.from(grid.querySelectorAll('.placeholder')); const groot = document.getElementById('groot'); let currentIndex = 0; function computePositions(){ const stageRect = grid.getBoundingClientRect(); return placeholders.map(ph => { const r = ph.getBoundingClientRect(); return { x: r.left - stageRect.left + r.width/2, y: r.top - stageRect.top + r.height/2 }; }); } function moveTo(index){ const pos = positions[index]; if(!pos) return; const imgW = groot.offsetWidth, imgH = groot.offsetHeight; const stageRect = grid.getBoundingClientRect(); const margin = 10; let tx = pos.x - imgW/2; let ty = pos.y - imgH/2; tx = Math.max(margin, Math.min(tx, stageRect.width - imgW - margin)); ty = Math.max(margin, Math.min(ty, stageRect.height - imgH - margin)); groot.style.transform = `translate(${tx}px, ${ty}px)`; currentIndex = index; } function differentIndex(exclude){ const choices = [0,1,2,3].filter(i=>i!==exclude); return choices[Math.floor(Math.random()*choices.length)]; } let positions = computePositions(); window.addEventListener('resize', ()=>{ positions = computePositions(); moveTo(currentIndex); }); requestAnimationFrame(()=>{ positions = computePositions(); moveTo(currentIndex); }); // دکمهها: روی کلیک یا فوکوس document.querySelectorAll('.controls button').forEach(btn => { const handler = () => { const target = +btn.dataset.target; const dest = currentIndex === target ? differentIndex(currentIndex) : target; moveTo(dest); }; btn.addEventListener('click', handler); btn.addEventListener('focus', handler); }); // گروت: فرار از لمس یا هاور const escapeGroot = () => { moveTo(differentIndex(currentIndex)); }; groot.addEventListener('mouseenter', escapeGroot); groot.addEventListener('touchstart', (e) => { e.preventDefault(); // جلوگیری از رفتار پیشفرض لمس escapeGroot(); }); // حذف pointermove برای جلوگیری از واکنشهای بیش از حد در موبایل })();