InnovationLab / ar.html
MatteoScript's picture
Update ar.html
3cedbca verified
raw
history blame
19.1 kB
<!DOCTYPE html>
<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 !important;
font-family: 'Fira Code', monospace;
overflow: hidden;
position: fixed;
}
/* --- ENGINE GRAFICO (Camera e Canvas) --- */
video {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
min-width: 100vw !important;
min-height: 100vh !important;
object-fit: cover !important;
z-index: -2 !important;
margin: 0 !important;
padding: 0 !important;
}
.a-canvas {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: -1 !important;
margin: 0 !important;
padding: 0 !important;
}
.a-scene {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
margin: 0 !important;
padding: 0 !important;
}
.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 !important; }
#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 !important;
width: 100% !important;
height: auto !important;
min-width: auto !important;
min-height: auto !important;
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>