Spaces:
Running
Running
| <html lang="it"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" /> | |
| <title>AR Neural Link | Vertical Native</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet"> | |
| <script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/mind-ar@1.2.2/dist/mindar-image.prod.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/mind-ar@1.2.2/dist/mindar-image-aframe.prod.js"></script> | |
| <style> | |
| :root { | |
| --neon-green: #00ff41; | |
| --dark-bg: #050505; | |
| --error-red: #ff0055; | |
| } | |
| html, body { | |
| margin: 0; | |
| padding: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: transparent ; | |
| font-family: 'Fira Code', monospace; | |
| overflow: hidden; | |
| position: fixed; | |
| } | |
| /* --- ENGINE GRAFICO (Camera e Canvas) --- */ | |
| video { | |
| position: fixed ; | |
| top: 0 ; | |
| left: 0 ; | |
| width: 100vw ; | |
| height: 100vh ; | |
| min-width: 100vw ; | |
| min-height: 100vh ; | |
| object-fit: cover ; | |
| z-index: -2 ; | |
| margin: 0 ; | |
| padding: 0 ; | |
| } | |
| .a-canvas { | |
| position: fixed ; | |
| top: 0 ; | |
| left: 0 ; | |
| width: 100vw ; | |
| height: 100vh ; | |
| z-index: -1 ; | |
| margin: 0 ; | |
| padding: 0 ; | |
| } | |
| .a-scene { | |
| position: fixed ; | |
| top: 0 ; | |
| left: 0 ; | |
| width: 100vw ; | |
| height: 100vh ; | |
| margin: 0 ; | |
| padding: 0 ; | |
| } | |
| .scanlines { | |
| background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0) 50%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.2)); | |
| background-size: 100% 4px; | |
| position: fixed; inset: 0; pointer-events: none; | |
| z-index: 10; | |
| opacity: 0.4; | |
| } | |
| .tech-border { | |
| border: 1px solid var(--neon-green); | |
| box-shadow: 0 0 15px rgba(0, 255, 65, 0.15); | |
| background: rgba(0,0,0,0.85); | |
| backdrop-filter: blur(8px); | |
| } | |
| .a-enter-vr-button { display: none ; } | |
| #custom-loader { | |
| position: fixed; inset: 0; z-index: 9999; | |
| background: #000; | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| transition: opacity 0.5s ease-out; | |
| padding: 20px; | |
| } | |
| .glitch-text { animation: glitch 2s infinite; } | |
| @keyframes glitch { | |
| 0% { transform: translate(0); } | |
| 20% { transform: translate(-2px, 2px); } | |
| 40% { transform: translate(-2px, -2px); } | |
| 60% { transform: translate(2px, 2px); } | |
| 80% { transform: translate(2px, -2px); } | |
| 100% { transform: translate(0); } | |
| } | |
| .loader-track { | |
| width: 100%; max-width: 280px; height: 6px; | |
| background: #111; margin-top: 20px; | |
| overflow: hidden; border-radius: 4px; | |
| } | |
| .loader-fill { | |
| height: 100%; background: var(--neon-green); width: 0%; | |
| transition: width 0.3s; | |
| box-shadow: 0 0 10px var(--neon-green); | |
| } | |
| .safe-area-y { | |
| padding-top: env(safe-area-inset-top, 20px); | |
| padding-bottom: env(safe-area-inset-bottom, 20px); | |
| } | |
| /* FALLBACK VIDEO PLAYER */ | |
| #fallback-player { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| width: 90%; | |
| max-width: 500px; | |
| z-index: 1000; | |
| background: rgba(0,0,0,0.95); | |
| border: 2px solid var(--neon-green); | |
| border-radius: 12px; | |
| padding: 20px; | |
| display: none; | |
| box-shadow: 0 0 30px rgba(0, 255, 65, 0.3); | |
| } | |
| #fallback-player video { | |
| position: relative ; | |
| width: 100% ; | |
| height: auto ; | |
| min-width: auto ; | |
| min-height: auto ; | |
| border-radius: 8px; | |
| margin-bottom: 15px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- 1. LOADER --> | |
| <div id="custom-loader"> | |
| <div class="text-[#00ff41] text-5xl font-black tracking-tighter glitch-text mb-4"> | |
| LINK<br>START | |
| </div> | |
| <div class="text-white/50 text-xs font-mono uppercase tracking-[0.2em] mb-2" id="load-msg">Initializing AR Core...</div> | |
| <div class="loader-track"><div class="loader-fill" id="progress-bar"></div></div> | |
| <div id="loading-percent" class="text-[#00ff41] font-mono text-xl mt-2 font-bold">0%</div> | |
| </div> | |
| <!-- 2. FX --> | |
| <div class="scanlines"></div> | |
| <!-- 3. UI LAYER --> | |
| <div id="ui-layer" class="fixed inset-0 z-[50] flex flex-col justify-between safe-area-y pointer-events-none"> | |
| <!-- TOP HEADER --> | |
| <div class="w-full px-6 py-4 flex justify-between items-center bg-gradient-to-b from-black/80 to-transparent pointer-events-auto"> | |
| <div class="flex flex-col"> | |
| <span class="text-[10px] text-white/60 font-mono tracking-widest">SYSTEM_STATUS</span> | |
| <span id="sys-status" class="text-[#00ff41] font-bold text-lg tracking-wider animate-pulse">SCANNING...</span> | |
| <span class="text-[8px] text-white/40 font-mono mt-1">FPS: <span id="fps-counter">60</span> | LAT: 12ms</span> | |
| </div> | |
| <a href="./index.html" class="w-10 h-10 flex items-center justify-center border border-[#00ff41]/50 rounded-full bg-black/40 backdrop-blur-md active:scale-95 transition-transform"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#00ff41" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg> | |
| </a> | |
| </div> | |
| <!-- MIRINO --> | |
| <div id="aim-overlay" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center justify-center transition-opacity duration-300"> | |
| <div class="relative w-[65vw] h-[100vw] max-w-[300px] max-h-[500px] border border-white/20 rounded-xl"> | |
| <div class="absolute -top-1 -left-1 w-6 h-6 border-t-4 border-l-4 border-[#00ff41]"></div> | |
| <div class="absolute -top-1 -right-1 w-6 h-6 border-t-4 border-r-4 border-[#00ff41]"></div> | |
| <div class="absolute -bottom-1 -left-1 w-6 h-6 border-b-4 border-l-4 border-[#00ff41]"></div> | |
| <div class="absolute -bottom-1 -right-1 w-6 h-6 border-b-4 border-r-4 border-[#00ff41]"></div> | |
| <div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full flex items-center justify-center"> | |
| <div class="w-12 h-[1px] bg-[#00ff41]/50"></div> | |
| <div class="h-12 w-[1px] bg-[#00ff41]/50 absolute"></div> | |
| </div> | |
| </div> | |
| <div class="mt-4 bg-black/60 backdrop-blur px-4 py-2 rounded border border-[#00ff41]/30"> | |
| <p class="text-[#00ff41] text-xs font-bold tracking-widest uppercase">Inquadra il Marker</p> | |
| </div> | |
| </div> | |
| <!-- BOTTOM CONTROLS --> | |
| <div class="w-full px-6 pb-8 pointer-events-auto flex flex-col items-center bg-gradient-to-t from-black/90 to-transparent"> | |
| <!-- Pulsante Audio --> | |
| <button id="audio-btn" class="w-full max-w-sm py-5 bg-[#00ff41]/10 border border-[#00ff41] text-[#00ff41] font-bold text-lg uppercase tracking-[0.2em] rounded active:bg-[#00ff41] active:text-black transition-all mb-3 flex items-center justify-center gap-3 backdrop-blur-md"> | |
| <span>🔊</span> | |
| <span id="audio-text">Attiva Audio</span> | |
| </button> | |
| <!-- NUOVO: Pulsante Fallback --> | |
| <button id="fallback-btn" class="w-full max-w-sm py-4 bg-[#ff0055]/10 border border-[#ff0055] text-[#ff0055] font-bold text-sm uppercase tracking-[0.2em] rounded active:bg-[#ff0055] active:text-white transition-all mb-4 flex items-center justify-center gap-2 backdrop-blur-md"> | |
| <span>⚠️</span> | |
| <span>Mostra Video (Fallback)</span> | |
| </button> | |
| <div class="text-[10px] text-white/40 font-mono text-center"> | |
| <div>NEURAL_LINK v2.4.0 // VERTICAL_MODE</div> | |
| <div class="mt-1">Built with 🧠 & ☕ by a sleep-deprived dev</div> | |
| <div class="text-[#00ff41]/60 mt-1" id="konami-hint">// Try: ↑↑↓↓←→←→BA</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 4. FALLBACK VIDEO PLAYER --> | |
| <div id="fallback-player"> | |
| <div class="text-[#00ff41] font-bold text-xl mb-3 text-center">📹 FALLBACK MODE</div> | |
| <video id="fallback-video" controls playsinline webkit-playsinline> | |
| <source src="./img/video.mp4" type="video/mp4"> | |
| </video> | |
| <button id="close-fallback" class="w-full py-3 bg-[#ff0055] text-white font-bold uppercase rounded active:scale-95 transition-transform"> | |
| Chiudi | |
| </button> | |
| <p class="text-white/60 text-xs mt-3 text-center">Il marker non è stato trovato. Usa questo player manuale.</p> | |
| </div> | |
| <!-- 5. AR SCENE --> | |
| <a-scene | |
| mindar-image="imageTargetSrc: img/targets.mind; filterMinCF:0.00001; filterBeta: 10; uiLoading: no; uiScanning: no; missTolerance: 25; warmupTolerance: 2" | |
| color-space="sRGB" | |
| renderer="colorManagement: true, physicallyCorrectLights, highRefreshRate: true" | |
| vr-mode-ui="enabled: false" | |
| device-orientation-permission-ui="enabled: false"> | |
| <a-assets> | |
| <video id="vid" src="./img/video.mp4" preload="auto" loop muted playsinline webkit-playsinline crossorigin="anonymous"></video> | |
| </a-assets> | |
| <a-camera position="0 0 0" look-controls="enabled: false"></a-camera> | |
| <a-entity id="example-target" mindar-image-target="targetIndex: 0"> | |
| <!-- VIDEO 16:9 --> | |
| <a-entity id="myVid" | |
| geometry="primitive: plane; width: 1.6; height: 0.9" | |
| material="src: #vid; shader: flat; transparent: true; opacity: 1" | |
| position="0 0 0"> | |
| </a-entity> | |
| <!-- Cornice Cyberpunk 16:9 --> | |
| <a-plane position="0 0.47 0" width="1.68" height="0.03" color="#00ff41" material="shader: flat"> | |
| <a-animation attribute="opacity" from="1" to="0.7" dur="100" direction="alternate" repeat="indefinite"></a-animation> | |
| </a-plane> | |
| <a-plane position="0 -0.47 0" width="1.68" height="0.03" color="#00ff41" material="shader: flat"></a-plane> | |
| <a-plane position="-0.83 0 0" width="0.03" height="0.96" color="#00ff41" material="shader: flat"></a-plane> | |
| <a-plane position="0.83 0 0" width="0.03" height="0.96" color="#00ff41" material="shader: flat"> | |
| <a-animation attribute="opacity" from="1" to="0.7" dur="150" direction="alternate" repeat="indefinite"></a-animation> | |
| </a-plane> | |
| <a-plane position="-0.77 0.41 0.01" width="0.15" height="0.03" color="white" material="shader: flat; opacity: 0.9"></a-plane> | |
| <a-plane position="0.77 -0.41 0.01" width="0.15" height="0.03" color="white" material="shader: flat; opacity: 0.9"></a-plane> | |
| <a-text value="HACK_THE_PLANET.exe" color="#00ff41" align="center" width="1.5" position="0 -0.6 0.01" | |
| font="https://cdn.aframe.io/fonts/Roboto-msdf.json"> | |
| <a-animation attribute="opacity" from="0.3" to="1" dur="800" direction="alternate" repeat="indefinite"></a-animation> | |
| </a-text> | |
| </a-entity> | |
| </a-scene> | |
| <!-- 6. LOGIC + NERD EASTER EGGS --> | |
| <script> | |
| const video = document.querySelector("#vid"); | |
| const target = document.querySelector("#example-target"); | |
| const statusText = document.querySelector("#sys-status"); | |
| const aimOverlay = document.querySelector("#aim-overlay"); | |
| const audioBtn = document.querySelector("#audio-btn"); | |
| const audioText = document.querySelector("#audio-text"); | |
| const loader = document.querySelector("#custom-loader"); | |
| const loadingPercent = document.querySelector("#loading-percent"); | |
| const progressBar = document.querySelector("#progress-bar"); | |
| const scene = document.querySelector("a-scene"); | |
| const fpsCounter = document.querySelector("#fps-counter"); | |
| const fallbackBtn = document.querySelector("#fallback-btn"); | |
| const fallbackPlayer = document.querySelector("#fallback-player"); | |
| const fallbackVideo = document.querySelector("#fallback-video"); | |
| const closeFallback = document.querySelector("#close-fallback"); | |
| let isAudioEnabled = false; | |
| let loadProgress = 0; | |
| // Easter Egg 1: Fake FPS Counter | |
| setInterval(() => { | |
| const fakeFps = Math.floor(Math.random() * 3) + 58; | |
| fpsCounter.innerText = fakeFps; | |
| }, 500); | |
| // Easter Egg 2: Konami Code | |
| const konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a']; | |
| let konamiIndex = 0; | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === konamiCode[konamiIndex]) { | |
| konamiIndex++; | |
| if (konamiIndex === konamiCode.length) { | |
| alert('🎮 CHEAT CODE ACTIVATED!\n\n"In the Matrix, no one can hear you printf()"\n- Anonymous Hacker, 1999'); | |
| konamiIndex = 0; | |
| } | |
| } else { | |
| konamiIndex = 0; | |
| } | |
| }); | |
| // Console Easter Egg | |
| console.log("%c⚡ NEURAL LINK SYSTEM INITIALIZED", "color: #00ff41; font-size: 20px; font-weight: bold;"); | |
| console.log("%cIf you're reading this, you're a true nerd 🤓", "color: #fff; font-size: 12px;"); | |
| console.log("%c// TODO: Add more bugs for job security", "color: #666; font-style: italic;"); | |
| // Loading con messaggi nerd | |
| const nerdMessages = [ | |
| "Compiling shaders...", | |
| "Downloading RAM...", | |
| "Adjusting flux capacitor...", | |
| "Hacking the mainframe...", | |
| "Dividing by zero...", | |
| "Reticulating splines..." | |
| ]; | |
| let msgIndex = 0; | |
| const loadInterval = setInterval(() => { | |
| loadProgress += 2; | |
| if(loadProgress > 100) loadProgress = 100; | |
| loadingPercent.innerText = loadProgress + "%"; | |
| progressBar.style.width = loadProgress + "%"; | |
| if(loadProgress % 15 === 0 && msgIndex < nerdMessages.length) { | |
| document.querySelector('#load-msg').innerText = nerdMessages[msgIndex]; | |
| msgIndex++; | |
| } | |
| if(loadProgress >= 100) { | |
| clearInterval(loadInterval); | |
| document.querySelector('#load-msg').innerText = "System ready. Let's hack reality."; | |
| } | |
| }, 30); | |
| // AR PRONTA | |
| scene.addEventListener("arReady", () => { | |
| console.log("%c✅ AR SYSTEM ONLINE", "color: #00ff41; font-weight: bold;"); | |
| setTimeout(() => { | |
| loader.style.opacity = "0"; | |
| setTimeout(() => loader.style.display = "none", 500); | |
| }, 500); | |
| }); | |
| // ERROR HANDLING | |
| scene.addEventListener("arError", (ev) => { | |
| console.error("💀 FATAL ERROR:", ev); | |
| alert("⚠️ Camera Access Denied!\n\nPlease grant camera permissions or check if another app is using it.\n\n(Yes, we need it. No, we won't spy on you. Probably.)"); | |
| }); | |
| // TARGET FOUND | |
| target.addEventListener("targetFound", () => { | |
| console.log("🎯 TARGET ACQUIRED"); | |
| video.play(); | |
| statusText.innerText = "LOCKED_ON"; | |
| statusText.style.color = "#fff"; | |
| statusText.classList.remove("animate-pulse"); | |
| aimOverlay.style.opacity = "0"; | |
| if(navigator.vibrate) navigator.vibrate([30, 10, 30]); | |
| }); | |
| // TARGET LOST | |
| target.addEventListener("targetLost", () => { | |
| console.log("❌ TARGET LOST"); | |
| video.pause(); | |
| statusText.innerText = "SEARCHING..."; | |
| statusText.style.color = "#00ff41"; | |
| statusText.classList.add("animate-pulse"); | |
| aimOverlay.style.opacity = "1"; | |
| }); | |
| // AUDIO TOGGLE | |
| audioBtn.addEventListener('click', () => { | |
| if (!isAudioEnabled) { | |
| video.muted = false; | |
| fallbackVideo.muted = false; | |
| isAudioEnabled = true; | |
| audioText.innerText = "AUDIO ON"; | |
| audioBtn.classList.add("bg-[#00ff41]", "text-black"); | |
| audioBtn.classList.remove("bg-[#00ff41]/10", "text-[#00ff41]"); | |
| console.log("🔊 Audio stream activated"); | |
| if(navigator.vibrate) navigator.vibrate(50); | |
| setTimeout(() => { | |
| audioBtn.style.opacity = "0"; | |
| audioBtn.style.pointerEvents = "none"; | |
| }, 1500); | |
| } | |
| }); | |
| // FALLBACK MODE | |
| fallbackBtn.addEventListener('click', () => { | |
| fallbackPlayer.style.display = 'block'; | |
| fallbackVideo.play(); | |
| console.log("🆘 FALLBACK MODE ACTIVATED"); | |
| if(navigator.vibrate) navigator.vibrate(100); | |
| }); | |
| closeFallback.addEventListener('click', () => { | |
| fallbackPlayer.style.display = 'none'; | |
| fallbackVideo.pause(); | |
| }); | |
| // Easter Egg 3: Double tap | |
| let lastTap = 0; | |
| document.addEventListener('touchend', (e) => { | |
| const currentTime = new Date().getTime(); | |
| const tapLength = currentTime - lastTap; | |
| if (tapLength < 300 && tapLength > 0) { | |
| console.log("🤫 Secret message: There is no spoon."); | |
| } | |
| lastTap = currentTime; | |
| }); | |
| </script> | |
| </body> | |
| </html> |