| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>MorphoWeb 3D - Bac à Sable Enfant</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script src="https://unpkg.com/feather-icons"></script> |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
| <link href="https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap" rel="stylesheet"> |
| <style> |
| body { |
| font-family: 'Comic Neue', cursive; |
| background-color: #f0f9ff; |
| cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%23f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/></svg>'), auto; |
| } |
| .shape { |
| transition: all 0.3s ease; |
| } |
| .shape:hover { |
| transform: scale(1.1) rotate(10deg); |
| } |
| #playground { |
| background-color: #fff; |
| border-radius: 20px; |
| box-shadow: 0 10px 20px rgba(0,0,0,0.1); |
| } |
| </style> |
| </head> |
| <body class="min-h-screen"> |
| <div class="container mx-auto px-4 py-8"> |
| <header class="flex items-center justify-center mb-8"> |
| <i data-feather="sun" class="text-yellow-400 w-12 h-12 mr-3"></i> |
| <h1 class="text-4xl font-bold text-blue-600">Bac à Sable Créatif</h1> |
| </header> |
|
|
| <div class="flex flex-wrap justify-center gap-6 mb-8"> |
| <button class="shape-btn bg-red-400 hover:bg-red-500 text-white text-xl px-6 py-3 rounded-full shadow-lg" data-shape="circle"> |
| <i data-feather="circle" class="inline mr-2"></i> Rond |
| </button> |
| <button class="shape-btn bg-blue-400 hover:bg-blue-500 text-white text-xl px-6 py-3 rounded-full shadow-lg" data-shape="square"> |
| <i data-feather="square" class="inline mr-2"></i> Carré |
| </button> |
| <button class="shape-btn bg-green-400 hover:bg-green-500 text-white text-xl px-6 py-3 rounded-full shadow-lg" data-shape="star"> |
| <i data-feather="star" class="inline mr-2"></i> Étoile |
| </button> |
| <button class="shape-btn bg-purple-400 hover:bg-purple-500 text-white text-xl px-6 py-3 rounded-full shadow-lg" data-shape="triangle"> |
| <i data-feather="triangle" class="inline mr-2"></i> Triangle |
| </button> |
| </div> |
|
|
| <div id="playground" class="w-full h-96 border-4 border-dashed border-blue-200 relative overflow-hidden"> |
| |
| </div> |
|
|
| <div class="mt-6 flex justify-center gap-4"> |
| <button id="clear-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-6 py-2 rounded-full text-lg"> |
| <i data-feather="trash-2" class="inline mr-2"></i> Effacer tout |
| </button> |
| <button id="animate-btn" class="bg-pink-400 hover:bg-pink-500 text-white px-6 py-2 rounded-full text-lg"> |
| <i data-feather="zap" class="inline mr-2"></i> Animer ! |
| </button> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', () => { |
| feather.replace(); |
| |
| const colors = ['#f87171', '#60a5fa', '#34d399', '#fbbf24', '#a78bfa']; |
| const playground = document.getElementById('playground'); |
| let shapes = []; |
| |
| document.querySelectorAll('.shape-btn').forEach(btn => { |
| btn.addEventListener('click', () => { |
| const shapeType = btn.dataset.shape; |
| const color = colors[Math.floor(Math.random() * colors.length)]; |
| |
| const shape = document.createElement('div'); |
| shape.className = 'shape absolute cursor-pointer'; |
| shape.style.width = '80px'; |
| shape.style.height = '80px'; |
| shape.style.backgroundColor = color; |
| shape.style.left = `${Math.random() * (playground.offsetWidth - 100)}px`; |
| shape.style.top = `${Math.random() * (playground.offsetHeight - 100)}px`; |
| |
| switch(shapeType) { |
| case 'circle': |
| shape.style.borderRadius = '50%'; |
| break; |
| case 'star': |
| shape.style.background = 'none'; |
| shape.innerHTML = `<svg width="80" height="80" viewBox="0 0 24 24" fill="${color}" stroke="none"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>`; |
| break; |
| case 'triangle': |
| shape.style.background = 'none'; |
| shape.innerHTML = `<svg width="80" height="80" viewBox="0 0 24 24" fill="${color}" stroke="none"><polygon points="12 2 22 22 2 22 12 2"/></svg>`; |
| break; |
| } |
| |
| shape.addEventListener('click', () => { |
| shape.style.transform = 'scale(1.2) rotate(20deg)'; |
| setTimeout(() => { |
| shape.style.transform = ''; |
| }, 300); |
| new Audio('https://assets.mixkit.co/sfx/preview/mixkit-positive-interface-beep-221.mp3').play(); |
| }); |
| |
| shape.draggable = true; |
| shape.addEventListener('dragstart', (e) => { |
| e.dataTransfer.setData('text/plain', ''); |
| setTimeout(() => shape.style.opacity = '0.4', 0); |
| }); |
| |
| shape.addEventListener('dragend', () => { |
| shape.style.opacity = '1'; |
| }); |
| |
| playground.appendChild(shape); |
| shapes.push(shape); |
| |
| |
| new Audio('https://assets.mixkit.co/sfx/preview/mixkit-unlock-game-notification-253.mp3').play(); |
| }); |
| }); |
| |
| playground.addEventListener('dragover', (e) => { |
| e.preventDefault(); |
| }); |
| |
| playground.addEventListener('drop', (e) => { |
| e.preventDefault(); |
| const shape = document.elementFromPoint(e.clientX, e.clientY); |
| if (shape && shape.classList.contains('shape')) { |
| shape.style.left = `${e.pageX - playground.offsetLeft - 40}px`; |
| shape.style.top = `${e.pageY - playground.offsetTop - 40}px`; |
| } |
| }); |
| |
| document.getElementById('clear-btn').addEventListener('click', () => { |
| playground.innerHTML = ''; |
| shapes = []; |
| new Audio('https://assets.mixkit.co/sfx/preview/mixkit-arcade-retro-game-over-213.mp3').play(); |
| }); |
| |
| document.getElementById('animate-btn').addEventListener('click', () => { |
| shapes.forEach(shape => { |
| shape.style.transition = 'all 1s ease'; |
| shape.style.left = `${Math.random() * (playground.offsetWidth - 100)}px`; |
| shape.style.top = `${Math.random() * (playground.offsetHeight - 100)}px`; |
| shape.style.transform = `rotate(${Math.random() * 360}deg) scale(${0.5 + Math.random()})`; |
| |
| setTimeout(() => { |
| shape.style.transition = ''; |
| }, 1000); |
| }); |
| new Audio('https://assets.mixkit.co/sfx/preview/mixkit-quick-jump-arcade-game-239.mp3').play(); |
| }); |
| }); |
| </script> |
| </body> |
| </html> |