Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Moonlit Owl Animation</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/gsap@3.11.4/dist/gsap.min.js"></script> | |
| <style> | |
| body { | |
| margin: 0; | |
| overflow: hidden; | |
| background-color: #0a0a1a; | |
| } | |
| canvas { | |
| display: block; | |
| } | |
| #sound-btn { | |
| position: absolute; | |
| bottom: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background: rgba(255, 255, 255, 0.2); | |
| border: 2px solid white; | |
| color: white; | |
| padding: 10px 20px; | |
| border-radius: 30px; | |
| cursor: pointer; | |
| font-family: 'Arial', sans-serif; | |
| font-weight: bold; | |
| backdrop-filter: blur(5px); | |
| transition: all 0.3s ease; | |
| } | |
| #sound-btn:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: translateX(-50%) scale(1.05); | |
| } | |
| #instructions { | |
| position: absolute; | |
| top: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| color: white; | |
| text-align: center; | |
| font-family: 'Arial', sans-serif; | |
| background: rgba(0, 0, 0, 0.5); | |
| padding: 10px 20px; | |
| border-radius: 10px; | |
| font-size: 14px; | |
| } | |
| .moon { | |
| position: absolute; | |
| top: 50px; | |
| right: 50px; | |
| width: 80px; | |
| height: 80px; | |
| background: radial-gradient(circle, #f5f3ce 0%, #e8e6b5 70%); | |
| border-radius: 50%; | |
| box-shadow: 0 0 40px 15px rgba(245, 243, 206, 0.4); | |
| z-index: 1; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="moon"></div> | |
| <div id="instructions">Click the owl to hear it hoot!</div> | |
| <button id="sound-btn">Toggle Sound</button> | |
| <script> | |
| // Initialize Three.js scene | |
| const scene = new THREE.Scene(); | |
| const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
| const renderer = new THREE.WebGLRenderer({ antialias: true }); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| renderer.setClearColor(0x0a0a1a); | |
| document.body.appendChild(renderer.domElement); | |
| // Add stars | |
| const starsGeometry = new THREE.BufferGeometry(); | |
| const starsMaterial = new THREE.PointsMaterial({ | |
| color: 0xffffff, | |
| size: 0.1, | |
| transparent: true, | |
| opacity: 0.8 | |
| }); | |
| const starsVertices = []; | |
| for (let i = 0; i < 1000; i++) { | |
| const x = (Math.random() - 0.5) * 2000; | |
| const y = (Math.random() - 0.5) * 2000; | |
| const z = (Math.random() - 0.5) * 2000; | |
| starsVertices.push(x, y, z); | |
| } | |
| starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starsVertices, 3)); | |
| const stars = new THREE.Points(starsGeometry, starsMaterial); | |
| scene.add(stars); | |
| // Create owl | |
| const owlGroup = new THREE.Group(); | |
| scene.add(owlGroup); | |
| // Owl body | |
| const bodyGeometry = new THREE.SphereGeometry(1, 32, 32); | |
| const bodyMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x5a4a3a, | |
| shininess: 30 | |
| }); | |
| const body = new THREE.Mesh(bodyGeometry, bodyMaterial); | |
| owlGroup.add(body); | |
| // Owl head | |
| const headGeometry = new THREE.SphereGeometry(0.8, 32, 32); | |
| const headMaterial = new THREE.MeshPhongMaterial({ | |
| color: 0x5a4a3a, | |
| shininess: 30 | |
| }); | |
| const head = new THREE.Mesh(headGeometry, headMaterial); | |
| head.position.y = 0.8; | |
| owlGroup.add(head); | |
| // Owl eyes | |
| const eyeGeometry = new THREE.SphereGeometry(0.2, 32, 32); | |
| const eyeMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff }); | |
| const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
| leftEye.position.set(-0.3, 0.9, 0.6); | |
| owlGroup.add(leftEye); | |
| const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
| rightEye.position.set(0.3, 0.9, 0.6); | |
| owlGroup.add(rightEye); | |
| // Owl pupils | |
| const pupilGeometry = new THREE.SphereGeometry(0.1, 32, 32); | |
| const pupilMaterial = new THREE.MeshPhongMaterial({ color: 0x000000 }); | |
| const leftPupil = new THREE.Mesh(pupilGeometry, pupilMaterial); | |
| leftPupil.position.set(-0.3, 0.9, 0.8); | |
| owlGroup.add(leftPupil); | |
| const rightPupil = new THREE.Mesh(pupilGeometry, pupilMaterial); | |
| rightPupil.position.set(0.3, 0.9, 0.8); | |
| owlGroup.add(rightPupil); | |
| // Owl beak | |
| const beakGeometry = new THREE.ConeGeometry(0.1, 0.3, 32); | |
| const beakMaterial = new THREE.MeshPhongMaterial({ color: 0xf5a742 }); | |
| const beak = new THREE.Mesh(beakGeometry, beakMaterial); | |
| beak.position.set(0, 0.7, 0.8); | |
| beak.rotation.x = Math.PI / 2; | |
| owlGroup.add(beak); | |
| // Owl wings | |
| const wingGeometry = new THREE.SphereGeometry(0.8, 32, 32); | |
| wingGeometry.scale(1, 0.2, 0.5); | |
| const leftWing = new THREE.Mesh(wingGeometry, bodyMaterial); | |
| leftWing.position.set(-1, 0, 0); | |
| owlGroup.add(leftWing); | |
| const rightWing = new THREE.Mesh(wingGeometry, bodyMaterial); | |
| rightWing.position.set(1, 0, 0); | |
| owlGroup.add(rightWing); | |
| // Add lighting | |
| const moonLight = new THREE.PointLight(0xf5f3ce, 1, 100); | |
| moonLight.position.set(10, 10, 10); | |
| scene.add(moonLight); | |
| const ambientLight = new THREE.AmbientLight(0x404040); | |
| scene.add(ambientLight); | |
| // Position camera | |
| camera.position.z = 5; | |
| // Animation variables | |
| let wingFlapSpeed = 0.1; | |
| let owlPosition = { x: 0, y: 0, z: 0 }; | |
| let targetPosition = { x: 0, y: 0, z: 0 }; | |
| let flightPath = []; | |
| let currentPathIndex = 0; | |
| // Generate random flight path | |
| for (let i = 0; i < 10; i++) { | |
| flightPath.push({ | |
| x: (Math.random() - 0.5) * 10, | |
| y: (Math.random() - 0.5) * 5, | |
| z: (Math.random() - 0.5) * 10 | |
| }); | |
| } | |
| // Sound setup | |
| let audioContext; | |
| let gainNode; | |
| let soundEnabled = true; | |
| const soundBtn = document.getElementById('sound-btn'); | |
| function initAudio() { | |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
| gainNode = audioContext.createGain(); | |
| gainNode.gain.value = 0.5; | |
| gainNode.connect(audioContext.destination); | |
| } | |
| function playHoot() { | |
| if (!soundEnabled || !audioContext) return; | |
| const oscillator = audioContext.createOscillator(); | |
| const gain = audioContext.createGain(); | |
| oscillator.type = 'sine'; | |
| oscillator.frequency.setValueAtTime(300, audioContext.currentTime); | |
| oscillator.frequency.exponentialRampToValueAtTime(200, audioContext.currentTime + 0.5); | |
| gain.gain.setValueAtTime(0.3, audioContext.currentTime); | |
| gain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.5); | |
| oscillator.connect(gain); | |
| gain.connect(gainNode); | |
| oscillator.start(); | |
| oscillator.stop(audioContext.currentTime + 0.5); | |
| } | |
| // Toggle sound | |
| soundBtn.addEventListener('click', () => { | |
| soundEnabled = !soundEnabled; | |
| soundBtn.textContent = soundEnabled ? 'Sound: ON' : 'Sound: OFF'; | |
| }); | |
| // Owl click event | |
| renderer.domElement.addEventListener('click', (event) => { | |
| const mouse = new THREE.Vector2( | |
| (event.clientX / window.innerWidth) * 2 - 1, | |
| -(event.clientY / window.innerHeight) * 2 + 1 | |
| ); | |
| const raycaster = new THREE.Raycaster(); | |
| raycaster.setFromCamera(mouse, camera); | |
| const intersects = raycaster.intersectObject(owlGroup, true); | |
| if (intersects.length > 0) { | |
| playHoot(); | |
| // Change flight path when clicked | |
| currentPathIndex = (currentPathIndex + 1) % flightPath.length; | |
| targetPosition = flightPath[currentPathIndex]; | |
| // Increase wing flap speed temporarily | |
| wingFlapSpeed = 0.3; | |
| setTimeout(() => { wingFlapSpeed = 0.1; }, 1000); | |
| } | |
| }); | |
| // Handle window resize | |
| window.addEventListener('resize', () => { | |
| camera.aspect = window.innerWidth / window.innerHeight; | |
| camera.updateProjectionMatrix(); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| }); | |
| // Animation loop | |
| function animate() { | |
| requestAnimationFrame(animate); | |
| // Update owl position towards target | |
| owlPosition.x += (targetPosition.x - owlPosition.x) * 0.01; | |
| owlPosition.y += (targetPosition.y - owlPosition.y) * 0.01; | |
| owlPosition.z += (targetPosition.z - owlPosition.z) * 0.01; | |
| owlGroup.position.set(owlPosition.x, owlPosition.y, owlPosition.z); | |
| // Make owl look forward in its direction of movement | |
| if (Math.abs(targetPosition.x - owlPosition.x) > 0.1 || | |
| Math.abs(targetPosition.z - owlPosition.z) > 0.1) { | |
| const angle = Math.atan2( | |
| targetPosition.x - owlPosition.x, | |
| targetPosition.z - owlPosition.z | |
| ); | |
| owlGroup.rotation.y = angle; | |
| } | |
| // Wing flapping animation | |
| const time = Date.now() * 0.001; | |
| leftWing.rotation.z = Math.sin(time * 5 * wingFlapSpeed) * 0.5; | |
| rightWing.rotation.z = -Math.sin(time * 5 * wingFlapSpeed) * 0.5; | |
| // Rotate stars for parallax effect | |
| stars.rotation.y += 0.0001; | |
| renderer.render(scene, camera); | |
| } | |
| // Initialize audio and start animation | |
| initAudio(); | |
| animate(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=aicoding101/j-j" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |