|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>UAP Pulse - Advanced Atmospheric Tracking</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/qrcode.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js"></script> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); |
|
|
|
body { |
|
font-family: 'Space Grotesk', sans-serif; |
|
background-color: #0f172a; |
|
color: #e2e8f0; |
|
} |
|
|
|
.post-card { |
|
background: linear-gradient(145deg, #1e293b, #0f172a); |
|
border-left: 3px solid #3b82f6; |
|
transition: transform 0.2s; |
|
} |
|
|
|
.post-card:hover { |
|
transform: translateY(-2px); |
|
} |
|
|
|
.nav-item { |
|
position: relative; |
|
} |
|
|
|
.nav-item::after { |
|
content: ''; |
|
position: absolute; |
|
width: 0; |
|
height: 2px; |
|
bottom: 0; |
|
left: 0; |
|
background-color: #3b82f6; |
|
transition: width 0.3s; |
|
} |
|
|
|
.nav-item:hover::after { |
|
width: 100%; |
|
} |
|
|
|
.typewriter { |
|
overflow: hidden; |
|
border-right: 2px solid #3b82f6; |
|
white-space: nowrap; |
|
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite; |
|
} |
|
|
|
@keyframes typing { |
|
from { width: 0 } |
|
to { width: 100% } |
|
} |
|
|
|
@keyframes blink-caret { |
|
from, to { border-color: transparent } |
|
50% { border-color: #3b82f6 } |
|
} |
|
|
|
.glow { |
|
text-shadow: 0 0 10px rgba(59, 130, 246, 0.7); |
|
} |
|
|
|
|
|
.scanner-window { |
|
position: relative; |
|
width: 100%; |
|
height: 400px; |
|
background-color: #000; |
|
border: 2px solid #3b82f6; |
|
border-radius: 8px; |
|
overflow: hidden; |
|
margin-bottom: 20px; |
|
} |
|
|
|
.scanner-overlay { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: linear-gradient(transparent 70%, rgba(59, 130, 246, 0.1) 100%); |
|
pointer-events: none; |
|
} |
|
|
|
.scanner-grid { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background-image: |
|
linear-gradient(rgba(59, 130, 246, 0.3) 1px, transparent 1px), |
|
linear-gradient(90deg, rgba(59, 130, 246, 0.3) 1px, transparent 1px); |
|
background-size: 20px 20px; |
|
opacity: 0.5; |
|
} |
|
|
|
.scanner-crosshair { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
width: 30px; |
|
height: 30px; |
|
border: 2px solid rgba(255, 0, 0, 0.7); |
|
border-radius: 50%; |
|
} |
|
|
|
.scanner-crosshair::before, .scanner-crosshair::after { |
|
content: ''; |
|
position: absolute; |
|
background-color: rgba(255, 0, 0, 0.7); |
|
} |
|
|
|
.scanner-crosshair::before { |
|
width: 2px; |
|
height: 10px; |
|
top: -12px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
} |
|
|
|
.scanner-crosshair::after { |
|
width: 10px; |
|
height: 2px; |
|
top: 50%; |
|
left: -12px; |
|
transform: translateY(-50%); |
|
} |
|
|
|
.scanner-coordinates { |
|
position: absolute; |
|
bottom: 10px; |
|
left: 10px; |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 5px 10px; |
|
border-radius: 4px; |
|
font-family: monospace; |
|
color: #3b82f6; |
|
} |
|
|
|
.scanner-controls { |
|
position: absolute; |
|
bottom: 10px; |
|
right: 10px; |
|
display: flex; |
|
gap: 10px; |
|
} |
|
|
|
.scanner-btn { |
|
background-color: rgba(59, 130, 246, 0.7); |
|
color: white; |
|
border: none; |
|
border-radius: 50%; |
|
width: 40px; |
|
height: 40px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
cursor: pointer; |
|
transition: all 0.2s; |
|
} |
|
|
|
.scanner-btn:hover { |
|
background-color: rgba(59, 130, 246, 1); |
|
transform: scale(1.1); |
|
} |
|
|
|
.scanner-btn.active { |
|
background-color: rgba(239, 68, 68, 0.7); |
|
} |
|
|
|
.scanner-btn.active:hover { |
|
background-color: rgba(239, 68, 68, 1); |
|
} |
|
|
|
.uap-marker { |
|
position: absolute; |
|
width: 10px; |
|
height: 10px; |
|
background-color: red; |
|
border-radius: 50%; |
|
transform: translate(-50%, -50%); |
|
box-shadow: 0 0 10px red; |
|
animation: pulse 1.5s infinite; |
|
} |
|
|
|
@keyframes pulse { |
|
0% { transform: translate(-50%, -50%) scale(1); opacity: 1; } |
|
50% { transform: translate(-50%, -50%) scale(1.5); opacity: 0.7; } |
|
100% { transform: translate(-50%, -50%) scale(1); opacity: 1; } |
|
} |
|
|
|
.uap-info { |
|
position: absolute; |
|
background-color: rgba(0, 0, 0, 0.8); |
|
border: 1px solid #3b82f6; |
|
border-radius: 4px; |
|
padding: 5px; |
|
color: white; |
|
font-size: 12px; |
|
pointer-events: none; |
|
transform: translate(15px, -50%); |
|
min-width: 120px; |
|
display: none; |
|
} |
|
|
|
.uap-info::before { |
|
content: ''; |
|
position: absolute; |
|
left: -10px; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
border-width: 5px; |
|
border-style: solid; |
|
border-color: transparent #3b82f6 transparent transparent; |
|
} |
|
|
|
|
|
.viewer-3d { |
|
width: 100%; |
|
height: 400px; |
|
background-color: #000; |
|
border: 2px solid #3b82f6; |
|
border-radius: 8px; |
|
margin-top: 20px; |
|
position: relative; |
|
} |
|
|
|
.viewer-controls { |
|
position: absolute; |
|
bottom: 10px; |
|
left: 10px; |
|
z-index: 100; |
|
display: flex; |
|
gap: 10px; |
|
} |
|
|
|
.atmosphere-levels { |
|
position: absolute; |
|
right: 10px; |
|
top: 10px; |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 10px; |
|
border-radius: 4px; |
|
color: white; |
|
font-size: 12px; |
|
z-index: 100; |
|
} |
|
|
|
.atmosphere-level { |
|
margin-bottom: 5px; |
|
padding-left: 15px; |
|
position: relative; |
|
} |
|
|
|
.atmosphere-level::before { |
|
content: ''; |
|
position: absolute; |
|
left: 0; |
|
top: 50%; |
|
transform: translateY(-50%); |
|
width: 10px; |
|
height: 10px; |
|
border-radius: 50%; |
|
} |
|
|
|
.troposphere::before { background-color: #3b82f6; } |
|
.stratosphere::before { background-color: #10b981; } |
|
.mesosphere::before { background-color: #f59e0b; } |
|
.thermosphere::before { background-color: #ef4444; } |
|
.exosphere::before { background-color: #8b5cf6; } |
|
|
|
|
|
.shape-icon { |
|
width: 40px; |
|
height: 40px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin: 0 auto; |
|
} |
|
|
|
.triangle { |
|
width: 0; |
|
height: 0; |
|
border-left: 20px solid transparent; |
|
border-right: 20px solid transparent; |
|
border-bottom: 35px solid transparent; |
|
position: relative; |
|
} |
|
|
|
.triangle::before { |
|
content: ''; |
|
position: absolute; |
|
top: 5px; |
|
left: -20px; |
|
width: 0; |
|
height: 0; |
|
border-left: 20px solid transparent; |
|
border-right: 20px solid transparent; |
|
border-bottom: 35px solid white; |
|
filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.9)); |
|
} |
|
|
|
.triangle::after { |
|
content: ''; |
|
position: absolute; |
|
top: 6px; |
|
left: -18px; |
|
width: 0; |
|
height: 0; |
|
border-left: 18px solid transparent; |
|
border-right: 18px solid transparent; |
|
border-bottom: 32px solid #1e293b; |
|
} |
|
|
|
|
|
.measurement-band { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
pointer-events: none; |
|
} |
|
|
|
.measurement-line { |
|
position: absolute; |
|
background-color: rgba(59, 130, 246, 0.5); |
|
width: 2px; |
|
transform-origin: bottom center; |
|
} |
|
|
|
.measurement-label { |
|
position: absolute; |
|
color: white; |
|
font-size: 10px; |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 2px 4px; |
|
border-radius: 3px; |
|
white-space: nowrap; |
|
} |
|
|
|
|
|
.controls-panel { |
|
background-color: rgba(15, 23, 42, 0.9); |
|
border: 1px solid #3b82f6; |
|
border-radius: 8px; |
|
padding: 15px; |
|
margin-top: 20px; |
|
} |
|
|
|
.controls-title { |
|
font-size: 18px; |
|
font-weight: 600; |
|
color: #3b82f6; |
|
margin-bottom: 15px; |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.control-group { |
|
margin-bottom: 15px; |
|
} |
|
|
|
.control-label { |
|
display: block; |
|
margin-bottom: 5px; |
|
font-size: 14px; |
|
color: #e2e8f0; |
|
} |
|
|
|
.control-input { |
|
width: 100%; |
|
background-color: #1e293b; |
|
border: 1px solid #334155; |
|
border-radius: 4px; |
|
padding: 8px 12px; |
|
color: white; |
|
} |
|
|
|
.control-select { |
|
width: 100%; |
|
background-color: #1e293b; |
|
border: 1px solid #334155; |
|
border-radius: 4px; |
|
padding: 8px 12px; |
|
color: white; |
|
} |
|
|
|
.control-btn { |
|
background-color: #3b82f6; |
|
color: white; |
|
border: none; |
|
border-radius: 4px; |
|
padding: 8px 15px; |
|
cursor: pointer; |
|
transition: background-color 0.2s; |
|
} |
|
|
|
.control-btn:hover { |
|
background-color: #2563eb; |
|
} |
|
|
|
.slider-container { |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
} |
|
|
|
.slider-value { |
|
min-width: 40px; |
|
text-align: center; |
|
} |
|
|
|
|
|
.data-visualization { |
|
background-color: rgba(15, 23, 42, 0.9); |
|
border: 1px solid #3b82f6; |
|
border-radius: 8px; |
|
padding: 15px; |
|
margin-top: 20px; |
|
} |
|
|
|
.data-title { |
|
font-size: 18px; |
|
font-weight: 600; |
|
color: #3b82f6; |
|
margin-bottom: 15px; |
|
display: flex; |
|
align-items: center; |
|
} |
|
|
|
.data-value { |
|
font-family: monospace; |
|
color: white; |
|
margin-bottom: 5px; |
|
} |
|
|
|
.data-label { |
|
color: #94a3b8; |
|
font-size: 14px; |
|
} |
|
|
|
|
|
.radar-visualization { |
|
width: 100%; |
|
height: 200px; |
|
position: relative; |
|
margin-top: 15px; |
|
} |
|
|
|
.radar-circle { |
|
position: absolute; |
|
border: 1px solid rgba(59, 130, 246, 0.3); |
|
border-radius: 50%; |
|
transform: translate(-50%, -50%); |
|
} |
|
|
|
.radar-sweep { |
|
position: absolute; |
|
width: 100%; |
|
height: 100%; |
|
clip-path: polygon(50% 50%, 50% 0, 50% 0); |
|
background-color: rgba(59, 130, 246, 0.1); |
|
transform-origin: 50% 50%; |
|
animation: radarSweep 4s linear infinite; |
|
} |
|
|
|
@keyframes radarSweep { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
|
|
.radar-target { |
|
position: absolute; |
|
width: 8px; |
|
height: 8px; |
|
background-color: red; |
|
border-radius: 50%; |
|
transform: translate(-50%, -50%); |
|
box-shadow: 0 0 5px red; |
|
} |
|
</style> |
|
</head> |
|
<body class="min-h-screen"> |
|
|
|
<header class="bg-gradient-to-r from-blue-900 to-slate-900 shadow-lg"> |
|
<div class="container mx-auto px-4 py-6"> |
|
<div class="flex flex-col md:flex-row justify-between items-center"> |
|
<div class="flex items-center mb-4 md:mb-0"> |
|
<i class="fas fa-ufo text-3xl text-blue-400 mr-3"></i> |
|
<h1 class="text-2xl md:text-3xl font-bold text-white"> |
|
<span class="typewriter glow">UAP PULSE</span> |
|
</h1> |
|
</div> |
|
<nav class="flex space-x-6"> |
|
<a href="#" class="nav-item text-blue-300 hover:text-white py-2">Latest</a> |
|
<a href="#" class="nav-item text-blue-300 hover:text-white py-2">Reports</a> |
|
<a href="#" class="nav-item text-blue-300 hover:text-white py-2">Analysis</a> |
|
<a href="#" class="nav-item text-blue-300 hover:text-white py-2">Resources</a> |
|
</nav> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
|
|
<main class="container mx-auto px-4 py-8"> |
|
|
|
<section class="mb-12"> |
|
<h2 class="text-xl font-semibold text-white mb-4 flex items-center"> |
|
<i class="fas fa-satellite-dish text-blue-400 mr-2"></i> Advanced UAP Tracking System |
|
</h2> |
|
|
|
<div class="scanner-window" id="scannerWindow"> |
|
<div class="scanner-grid"></div> |
|
<div class="scanner-overlay"></div> |
|
<div class="scanner-crosshair"></div> |
|
<div class="measurement-band" id="measurementBand"></div> |
|
|
|
|
|
|
|
<div class="scanner-coordinates" id="scannerCoords"> |
|
Lat: 34.5362° | Long: -117.2928° | Alt: 831m | Victorville, CA |
|
</div> |
|
|
|
<div class="scanner-controls"> |
|
<button class="scanner-btn" id="startScanner" title="Start Scanner"> |
|
<i class="fas fa-play"></i> |
|
</button> |
|
<button class="scanner-btn" id="stopScanner" title="Stop Scanner"> |
|
<i class="fas fa-stop"></i> |
|
</button> |
|
<button class="scanner-btn" id="captureUAP" title="Capture UAP"> |
|
<i class="fas fa-camera"></i> |
|
</button> |
|
<button class="scanner-btn" id="toggleMeasurement" title="Toggle Measurement Band"> |
|
<i class="fas fa-ruler-combined"></i> |
|
</button> |
|
</div> |
|
|
|
<video id="scannerVideo" autoplay muted playsinline style="display: none;"></video> |
|
<canvas id="scannerCanvas" style="display: none;"></canvas> |
|
</div> |
|
|
|
|
|
<div class="controls-panel"> |
|
<h3 class="controls-title"> |
|
<i class="fas fa-sliders-h mr-2"></i> Tracking Parameters |
|
</h3> |
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6"> |
|
<div class="control-group"> |
|
<label class="control-label">Reference Satellite</label> |
|
<select class="control-select" id="satelliteSelect"> |
|
<option value="ISS">International Space Station (ISS)</option> |
|
<option value="HST">Hubble Space Telescope (HST)</option> |
|
<option value="GPS">GPS Satellite</option> |
|
<option value="STARLINK">Starlink Satellite</option> |
|
</select> |
|
</div> |
|
|
|
<div class="control-group"> |
|
<label class="control-label">Measurement Technique</label> |
|
<select class="control-select" id="techniqueSelect"> |
|
<option value="triangulation">Triangulation</option> |
|
<option value="ranging">LIDAR Ranging</option> |
|
<option value="radar">Radar Tracking</option> |
|
<option value="stereo">Stereoscopic Imaging</option> |
|
</select> |
|
</div> |
|
|
|
<div class="control-group"> |
|
<label class="control-label">Atmospheric Correction</label> |
|
<select class="control-select" id="atmosphereSelect"> |
|
<option value="standard">Standard Atmosphere</option> |
|
<option value="current">Current Conditions</option> |
|
<option value="none">None</option> |
|
</select> |
|
</div> |
|
</div> |
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4"> |
|
<div class="control-group"> |
|
<label class="control-label">Elevation Angle (°)</label> |
|
<div class="slider-container"> |
|
<input type="range" min="0" max="90" value="45" class="w-full" id="elevationSlider"> |
|
<span class="slider-value" id="elevationValue">45</span> |
|
</div> |
|
</div> |
|
|
|
<div class="control-group"> |
|
<label class="control-label">Azimuth Angle (°)</label> |
|
<div class="slider-container"> |
|
<input type="range" min="0" max="360" value="180" class="w-full" id="azimuthSlider"> |
|
<span class="slider-value" id="azimuthValue">180</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="flex justify-end mt-4"> |
|
<button class="control-btn" id="calculateBtn"> |
|
<i class="fas fa-calculator mr-2"></i> Calculate Position |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="data-visualization"> |
|
<h3 class="data-title"> |
|
<i class="fas fa-chart-line mr-2"></i> Tracking Data |
|
</h3> |
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6"> |
|
<div> |
|
<div class="data-label">Object Coordinates</div> |
|
<div class="data-value" id="objCoords">34.5362° N, -117.2928° W</div> |
|
<div class="data-value" id="objAltitude">0.0 km</div> |
|
</div> |
|
|
|
<div> |
|
<div class="data-label">Reference Satellite</div> |
|
<div class="data-value" id="satelliteName">ISS</div> |
|
<div class="data-value" id="satelliteDistance">400.0 km</div> |
|
</div> |
|
|
|
<div> |
|
<div class="data-label">Measurement Data</div> |
|
<div class="data-value" id="measurementType">Triangulation</div> |
|
<div class="data-value" id="measurementAccuracy">±50 m</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="radar-visualization" id="radarVisualization"> |
|
<div class="radar-circle" style="width: 40%; height: 40%; top: 50%; left: 50%;"></div> |
|
<div class="radar-circle" style="width: 70%; height: 70%; top: 50%; left: 50%;"></div> |
|
<div class="radar-circle" style="width: 100%; height: 100%; top: 50%; left: 50%;"></div> |
|
<div class="radar-sweep"></div> |
|
<div class="radar-target" style="top: 30%; left: 40%;"></div> |
|
<div class="radar-target" style="top: 60%; left: 70%;"></div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="viewer-3d" id="viewer3d"> |
|
<div class="viewer-controls"> |
|
<button class="scanner-btn" id="resetView" title="Reset View"> |
|
<i class="fas fa-crosshairs"></i> |
|
</button> |
|
<button class="scanner-btn" id="toggleOrbit" title="Toggle Orbit Controls"> |
|
<i class="fas fa-globe"></i> |
|
</button> |
|
<button class="scanner-btn" id="toggleAtmosphere" title="Toggle Atmosphere Layers"> |
|
<i class="fas fa-layer-group"></i> |
|
</button> |
|
</div> |
|
|
|
<div class="atmosphere-levels"> |
|
<div class="atmosphere-level troposphere">Troposphere (0-12km)</div> |
|
<div class="atmosphere-level stratosphere">Stratosphere (12-50km)</div> |
|
<div class="atmosphere-level mesosphere">Mesosphere (50-85km)</div> |
|
<div class="atmosphere-level thermosphere">Thermosphere (85-600km)</div> |
|
<div class="atmosphere-level exosphere">Exosphere (600km+)</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="mt-6 bg-slate-800/50 rounded-lg p-4 border border-slate-700"> |
|
<h3 class="font-medium text-white mb-3 flex items-center"> |
|
<i class="fas fa-list-ul text-blue-400 mr-2"></i> Tracked Objects |
|
</h3> |
|
<div class="overflow-x-auto"> |
|
<table class="min-w-full divide-y divide-slate-700"> |
|
<thead> |
|
<tr> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">ID</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Type</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Coordinates</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Altitude</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Layer</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Velocity</th> |
|
<th class="px-4 py-2 text-left text-xs font-medium text-slate-300 uppercase tracking-wider">Actions</th> |
|
</tr> |
|
</thead> |
|
<tbody id="uapTableBody" class="divide-y divide-slate-700"> |
|
|
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
</section> |
|
|
|
|
|
<section class="mb-12"> |
|
<div class="bg-gradient-to-br from-blue-900/50 to-slate-900/50 rounded-xl p-6 shadow-xl border border-blue-800/30"> |
|
<div class="flex items-center mb-4"> |
|
<span class="bg-blue-500 text-white text-xs font-semibold px-2.5 py-0.5 rounded">BREAKING</span> |
|
<span class="text-blue-300 text-sm ml-2">June 2024</span> |
|
</div> |
|
<h2 class="text-xl md:text-2xl font-bold text-white mb-3">New Atmospheric Tracking System Deployed in Victorville</h2> |
|
<p class="text-blue-100 mb-4">"The advanced measurement system combines satellite triangulation with ground-based sensors to precisely track unidentified aerial phenomena across all atmospheric layers" - Project Lead Dr. Elena Vasquez.</p> |
|
<div class="flex justify-between items-center"> |
|
<span class="text-xs text-blue-300">Source: UAP Research Initiative</span> |
|
<button class="text-blue-400 hover:text-blue-200 text-sm flex items-center" onclick="generateQR('New Atmospheric Tracking System Deployed in Victorville', 'https://uap-pulse.example.com/posts/2024-victorville-tracking')"> |
|
<i class="fas fa-qrcode mr-1"></i> QR Code |
|
</button> |
|
</div> |
|
</div> |
|
</section> |
|
</main> |
|
|
|
|
|
<footer class="bg-slate-900 mt-16 py-8 border-t border-slate-800"> |
|
<div class="container mx-auto px-4"> |
|
<div class="flex flex-col md:flex-row justify-between items-center"> |
|
<div class="mb-4 md:mb-0"> |
|
<div class="flex items-center"> |
|
<i class="fas fa-ufo text-2xl text-blue-400 mr-2"></i> |
|
<span class="text-xl font-bold text-white">UAP PULSE</span> |
|
</div> |
|
<p class="text-slate-400 text-sm mt-1">Advanced atmospheric tracking and UAP research</p> |
|
</div> |
|
|
|
<div class="flex space-x-6"> |
|
<a href="#" class="text-slate-400 hover:text-blue-300"> |
|
<i class="fab fa-twitter"></i> |
|
</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300"> |
|
<i class="fab fa-facebook"></i> |
|
</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300"> |
|
<i class="fab fa-reddit"></i> |
|
</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300"> |
|
<i class="fas fa-rss"></i> |
|
</a> |
|
</div> |
|
</div> |
|
|
|
<div class="border-t border-slate-800 mt-6 pt-6 flex flex-col md:flex-row justify-between items-center"> |
|
<p class="text-slate-500 text-sm mb-4 md:mb-0">© 2025 UAP Pulse. All rights reserved. Sponsored by SM+</p> |
|
<div class="flex space-x-4"> |
|
<a href="#" class="text-slate-400 hover:text-blue-300 text-sm">Privacy</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300 text-sm">Terms</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300 text-sm">Contact</a> |
|
<a href="#" class="text-slate-400 hover:text-blue-300 text-sm">Submit Report</a> |
|
</div> |
|
</div> |
|
</div> |
|
</footer> |
|
|
|
<script> |
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
const scannerWindow = document.getElementById('scannerWindow'); |
|
const scannerVideo = document.getElementById('scannerVideo'); |
|
const scannerCanvas = document.getElementById('scannerCanvas'); |
|
const scannerCoords = document.getElementById('scannerCoords'); |
|
const startScannerBtn = document.getElementById('startScanner'); |
|
const stopScannerBtn = document.getElementById('stopScanner'); |
|
const captureUAPBtn = document.getElementById('captureUAP'); |
|
const toggleMeasurementBtn = document.getElementById('toggleMeasurement'); |
|
const uapTableBody = document.getElementById('uapTableBody'); |
|
const measurementBand = document.getElementById('measurementBand'); |
|
|
|
|
|
const viewer3d = document.getElementById('viewer3d'); |
|
const resetViewBtn = document.getElementById('resetView'); |
|
const toggleOrbitBtn = document.getElementById('toggleOrbit'); |
|
const toggleAtmosphereBtn = document.getElementById('toggleAtmosphere'); |
|
|
|
|
|
const satelliteSelect = document.getElementById('satelliteSelect'); |
|
const techniqueSelect = document.getElementById('techniqueSelect'); |
|
const atmosphereSelect = document.getElementById('atmosphereSelect'); |
|
const elevationSlider = document.getElementById('elevationSlider'); |
|
const elevationValue = document.getElementById('elevationValue'); |
|
const azimuthSlider = document.getElementById('azimuthSlider'); |
|
const azimuthValue = document.getElementById('azimuthValue'); |
|
const calculateBtn = document.getElementById('calculateBtn'); |
|
|
|
|
|
const objCoords = document.getElementById('objCoords'); |
|
const objAltitude = document.getElementById('objAltitude'); |
|
const satelliteName = document.getElementById('satelliteName'); |
|
const satelliteDistance = document.getElementById('satelliteDistance'); |
|
const measurementType = document.getElementById('measurementType'); |
|
const measurementAccuracy = document.getElementById('measurementAccuracy'); |
|
|
|
|
|
let scene, camera, renderer, controls; |
|
let uapObjects = []; |
|
let orbitEnabled = true; |
|
let atmosphereLayersVisible = true; |
|
|
|
|
|
let detectedUAPs = []; |
|
let scannerActive = false; |
|
let scanInterval; |
|
let frameCount = 0; |
|
let measurementVisible = false; |
|
|
|
|
|
const viewerLocation = { |
|
lat: 34.5362, |
|
long: -117.2928, |
|
alt: 831 |
|
}; |
|
|
|
|
|
const satellites = { |
|
ISS: { name: "International Space Station", altitude: 408, color: 0x3b82f6 }, |
|
HST: { name: "Hubble Space Telescope", altitude: 540, color: 0x10b981 }, |
|
GPS: { name: "GPS Satellite", altitude: 20200, color: 0xf59e0b }, |
|
STARLINK: { name: "Starlink Satellite", altitude: 550, color: 0x8b5cf6 } |
|
}; |
|
|
|
|
|
const techniques = { |
|
triangulation: { name: "Triangulation", accuracy: "±50 m" }, |
|
ranging: { name: "LIDAR Ranging", accuracy: "±5 m" }, |
|
radar: { name: "Radar Tracking", accuracy: "±100 m" }, |
|
stereo: { name: "Stereoscopic", accuracy: "±20 m" } |
|
}; |
|
|
|
|
|
function initMeasurementBand() { |
|
|
|
measurementBand.innerHTML = ''; |
|
|
|
if (!measurementVisible) return; |
|
|
|
|
|
const angles = [0, 15, 30, 45, 60, 75, 90]; |
|
const distances = [10, 20, 50, 100, 200, 500]; |
|
|
|
|
|
distances.forEach(distance => { |
|
const line = document.createElement('div'); |
|
line.className = 'measurement-line'; |
|
line.style.height = `${distance / 5}%`; |
|
line.style.left = '50%'; |
|
line.style.bottom = '50%'; |
|
line.style.transform = 'translateX(-50%) rotate(0deg)'; |
|
line.style.opacity = '0.3'; |
|
measurementBand.appendChild(line); |
|
|
|
const label = document.createElement('div'); |
|
label.className = 'measurement-label'; |
|
label.textContent = `${distance} km`; |
|
label.style.left = '50%'; |
|
label.style.bottom = `${50 - distance / 10}%`; |
|
label.style.transform = 'translateX(-50%)'; |
|
measurementBand.appendChild(label); |
|
}); |
|
|
|
|
|
angles.forEach(angle => { |
|
const line = document.createElement('div'); |
|
line.className = 'measurement-line'; |
|
line.style.height = '40%'; |
|
line.style.left = '50%'; |
|
line.style.bottom = '50%'; |
|
line.style.transform = `translateX(-50%) rotate(${angle}deg)`; |
|
measurementBand.appendChild(line); |
|
|
|
const label = document.createElement('div'); |
|
label.className = 'measurement-label'; |
|
label.textContent = `${angle}°`; |
|
label.style.left = `${50 + Math.sin(angle * Math.PI / 180) * 20}%`; |
|
label.style.bottom = `${50 - Math.cos(angle * Math.PI / 180) * 20}%`; |
|
measurementBand.appendChild(label); |
|
}); |
|
} |
|
|
|
|
|
function updateMeasurement() { |
|
const elevation = parseFloat(elevationSlider.value); |
|
const azimuth = parseFloat(azimuthSlider.value); |
|
|
|
|
|
objAltitude.textContent = `${(elevation * 10).toFixed(1)} km`; |
|
|
|
|
|
const lat = viewerLocation.lat + (Math.random() * 0.2 - 0.1); |
|
const long = viewerLocation.long + (Math.random() * 0.2 - 0.1); |
|
objCoords.textContent = `${lat.toFixed(4)}° N, ${long.toFixed(4)}° W`; |
|
|
|
|
|
const selectedSatellite = satelliteSelect.value; |
|
satelliteName.textContent = satellites[selectedSatellite].name; |
|
satelliteDistance.textContent = `${satellites[selectedSatellite].altitude} km`; |
|
|
|
|
|
const selectedTechnique = techniqueSelect.value; |
|
measurementType.textContent = techniques[selectedTechnique].name; |
|
measurementAccuracy.textContent = techniques[selectedTechnique].accuracy; |
|
} |
|
|
|
|
|
function init3DViewer() { |
|
|
|
scene = new THREE.Scene(); |
|
scene.background = new THREE.Color(0x000000); |
|
|
|
|
|
camera = new THREE.PerspectiveCamera(75, viewer3d.clientWidth / viewer3d.clientHeight, 0.1, 10000); |
|
camera.position.z = 50; |
|
|
|
|
|
renderer = new THREE.WebGLRenderer({ antialias: true }); |
|
renderer.setSize(viewer3d.clientWidth, viewer3d.clientHeight); |
|
viewer3d.appendChild(renderer.domElement); |
|
|
|
|
|
controls = new THREE.OrbitControls(camera, renderer.domElement); |
|
controls.enableDamping = true; |
|
controls.dampingFactor = 0.25; |
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0x404040); |
|
scene.add(ambientLight); |
|
|
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); |
|
directionalLight.position.set(1, 1, 1); |
|
scene.add(directionalLight); |
|
|
|
|
|
const geometry = new THREE.SphereGeometry(15, 32, 32); |
|
const material = new THREE.MeshPhongMaterial({ |
|
color: 0x3b82f6, |
|
specular: 0x111111, |
|
shininess: 30 |
|
}); |
|
const earth = new THREE.Mesh(geometry, material); |
|
scene.add(earth); |
|
|
|
|
|
const addAtmosphereLayer = (radius, color, opacity) => { |
|
const layerGeometry = new THREE.SphereGeometry(radius, 32, 32); |
|
const layerMaterial = new THREE.MeshBasicMaterial({ |
|
color: color, |
|
side: THREE.BackSide, |
|
transparent: true, |
|
opacity: opacity |
|
}); |
|
const layer = new THREE.Mesh(layerGeometry, layerMaterial); |
|
layer.userData.isAtmosphere = true; |
|
scene.add(layer); |
|
return layer; |
|
}; |
|
|
|
|
|
const troposphere = addAtmosphereLayer(15.5, 0x3b82f6, 0.2); |
|
const stratosphere = addAtmosphereLayer(16, 0x10b981, 0.15); |
|
const mesosphere = addAtmosphereLayer(16.5, 0xf59e0b, 0.1); |
|
const thermosphere = addAtmosphereLayer(17.5, 0xef4444, 0.08); |
|
const exosphere = addAtmosphereLayer(20, 0x8b5cf6, 0.05); |
|
|
|
|
|
const viewerMarkerGeometry = new THREE.SphereGeometry(0.3, 16, 16); |
|
const viewerMarkerMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff }); |
|
const viewerMarker = new THREE.Mesh(viewerMarkerGeometry, viewerMarkerMaterial); |
|
|
|
|
|
const phi = (90 - viewerLocation.lat) * (Math.PI / 180); |
|
const theta = (viewerLocation.long + 180) * (Math.PI / 180); |
|
const radius = 15 + viewerLocation.alt / 100000; |
|
|
|
viewerMarker.position.set( |
|
radius * Math.sin(phi) * Math.cos(theta), |
|
radius * Math.cos(phi), |
|
radius * Math.sin(phi) * Math.sin(theta) |
|
); |
|
scene.add(viewerMarker); |
|
|
|
|
|
function addSatellite(satelliteType) { |
|
|
|
scene.children.forEach(child => { |
|
if (child.userData.isSatellite) { |
|
scene.remove(child); |
|
} |
|
}); |
|
|
|
const sat = satellites[satelliteType]; |
|
const satGeometry = new THREE.BoxGeometry(1, 1, 1); |
|
const satMaterial = new THREE.MeshPhongMaterial({ color: sat.color }); |
|
const satellite = new THREE.Mesh(satGeometry, satMaterial); |
|
satellite.userData.isSatellite = true; |
|
|
|
|
|
const satRadius = 15 + sat.altitude / 100; |
|
satellite.position.set(satRadius, 0, 0); |
|
satellite.lookAt(0, 0, 0); |
|
|
|
scene.add(satellite); |
|
} |
|
|
|
|
|
addSatellite('ISS'); |
|
|
|
|
|
window.addEventListener('resize', () => { |
|
camera.aspect = viewer3d.clientWidth / viewer3d.clientHeight; |
|
camera.updateProjectionMatrix(); |
|
renderer.setSize(viewer3d.clientWidth, viewer3d.clientHeight); |
|
}); |
|
|
|
|
|
function animate() { |
|
requestAnimationFrame(animate); |
|
|
|
if (orbitEnabled) { |
|
controls.update(); |
|
} |
|
|
|
|
|
scene.children.forEach(child => { |
|
if (child.userData.isSatellite) { |
|
child.rotation.y += 0.001; |
|
} |
|
}); |
|
|
|
renderer.render(scene, camera); |
|
} |
|
|
|
animate(); |
|
|
|
|
|
return { |
|
addSatellite: addSatellite, |
|
toggleAtmosphere: function(visible) { |
|
scene.children.forEach(child => { |
|
if (child.userData.isAtmosphere) { |
|
child.visible = visible; |
|
} |
|
}); |
|
} |
|
}; |
|
} |
|
|
|
|
|
function initScanner() { |
|
|
|
startScannerBtn.addEventListener('click', startScanner); |
|
stopScannerBtn.addEventListener('click', stopScanner); |
|
captureUAPBtn.addEventListener('click', captureUAP); |
|
toggleMeasurementBtn.addEventListener('click', toggleMeasurement); |
|
|
|
|
|
resetViewBtn.addEventListener('click', resetView); |
|
toggleOrbitBtn.addEventListener('click', toggleOrbitControls); |
|
toggleAtmosphereBtn.addEventListener('click', toggleAtmosphereLayers); |
|
|
|
|
|
elevationSlider.addEventListener('input', function() { |
|
elevationValue.textContent = this.value; |
|
updateMeasurement(); |
|
}); |
|
|
|
azimuthSlider.addEventListener('input', function() { |
|
azimuthValue.textContent = this.value; |
|
updateMeasurement(); |
|
}); |
|
|
|
satelliteSelect.addEventListener('change', function() { |
|
viewer3DControls.addSatellite(this.value); |
|
updateMeasurement(); |
|
}); |
|
|
|
techniqueSelect.addEventListener('change', updateMeasurement); |
|
atmosphereSelect.addEventListener('change', updateMeasurement); |
|
|
|
calculateBtn.addEventListener('click', calculatePosition); |
|
|
|
|
|
initMeasurementBand(); |
|
|
|
|
|
viewer3DControls = init3DViewer(); |
|
|
|
|
|
setTimeout(() => { |
|
simulateInitialDetection(); |
|
}, 1000); |
|
} |
|
|
|
|
|
function toggleMeasurement() { |
|
measurementVisible = !measurementVisible; |
|
toggleMeasurementBtn.classList.toggle('active'); |
|
initMeasurementBand(); |
|
} |
|
|
|
|
|
function toggleAtmosphereLayers() { |
|
atmosphereLayersVisible = !atmosphereLayersVisible; |
|
toggleAtmosphereBtn.classList.toggle('active'); |
|
viewer3DControls.toggleAtmosphere(atmosphereLayersVisible); |
|
} |
|
|
|
|
|
function calculatePosition() { |
|
const elevation = parseFloat(elevationSlider.value); |
|
const azimuth = parseFloat(azimuthSlider.value); |
|
const technique = techniqueSelect.value; |
|
const atmosphere = atmosphereSelect.value; |
|
|
|
|
|
calculateBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Calculating...'; |
|
calculateBtn.disabled = true; |
|
|
|
|
|
setTimeout(() => { |
|
|
|
const uapId = 'UAP-' + Date.now().toString().slice(-4); |
|
const shapes = ['triangle', 'circle', 'square', 'cylinder', 'chevron', 'tictac']; |
|
const shape = shapes[Math.floor(Math.random() * shapes.length)]; |
|
|
|
|
|
const lat = viewerLocation.lat + (Math.random() * 0.2 - 0.1); |
|
const long = viewerLocation.long + (Math.random() * 0.2 - 0.1); |
|
const altitude = elevation * 10 + (Math.random() * 20 - 10); |
|
|
|
|
|
let atmosphereLayer, atmosphereColor; |
|
if (altitude < 12) { |
|
atmosphereLayer = 'Troposphere'; |
|
atmosphereColor = '#3b82f6'; |
|
} else if (altitude < 50) { |
|
atmosphereLayer = 'Stratosphere'; |
|
atmosphereColor = '#10b981'; |
|
} else if (altitude < 85) { |
|
atmosphereLayer = 'Mesosphere'; |
|
atmosphereColor = '#f59e0b'; |
|
} else if (altitude < 600) { |
|
atmosphereLayer = 'Thermosphere'; |
|
atmosphereColor = '#ef4444'; |
|
} else { |
|
atmosphereLayer = 'Exosphere'; |
|
atmosphereColor = '#8b5cf6'; |
|
} |
|
|
|
|
|
const uap = { |
|
id: uapId, |
|
shape: shape, |
|
lat: lat, |
|
long: long, |
|
altitude: altitude.toFixed(2), |
|
atmosphere: atmosphereLayer, |
|
atmosphereColor: atmosphereColor, |
|
velocity: (Math.random() * 5000 + 500).toFixed(0) + ' km/h', |
|
timestamp: new Date().toLocaleTimeString(), |
|
technique: technique, |
|
satellite: satelliteSelect.value |
|
}; |
|
|
|
detectedUAPs.push(uap); |
|
addUAPToTable(uap); |
|
addUAPTo3DViewer(uap); |
|
|
|
|
|
calculateBtn.innerHTML = '<i class="fas fa-calculator mr-2"></i> Calculate Position'; |
|
calculateBtn.disabled = false; |
|
|
|
|
|
alert(`Successfully tracked object ${uapId} at ${altitude.toFixed(2)} km in the ${atmosphereLayer}`); |
|
}, 1500); |
|
} |
|
|
|
|
|
function simulateInitialDetection() { |
|
const initialUAPs = [ |
|
{ |
|
id: 'UAP-1001', |
|
shape: 'triangle', |
|
lat: 34.5362 + 0.05, |
|
long: -117.2928 - 0.03, |
|
altitude: '8.5', |
|
atmosphere: 'Troposphere', |
|
atmosphereColor: '#3b82f6', |
|
velocity: '1200 km/h', |
|
timestamp: new Date().toLocaleTimeString(), |
|
technique: 'radar', |
|
satellite: 'ISS' |
|
}, |
|
{ |
|
id: 'UAP-1002', |
|
shape: 'tictac', |
|
lat: 34.5362 - 0.12, |
|
long: -117.2928 + 0.08, |
|
altitude: '65.2', |
|
atmosphere: 'Mesosphere', |
|
atmosphereColor: '#f59e0b', |
|
velocity: '3500 km/h', |
|
timestamp: new Date().toLocaleTimeString(), |
|
technique: 'triangulation', |
|
satellite: 'ISS' |
|
}, |
|
{ |
|
id: 'UAP-1003', |
|
shape: 'circle', |
|
lat: 34.5362 + 0.18, |
|
long: -117.2928 + 0.15, |
|
altitude: '450.0', |
|
atmosphere: 'Thermosphere', |
|
atmosphereColor: '#ef4444', |
|
velocity: '28000 km/h', |
|
timestamp: new Date().toLocaleTimeString(), |
|
technique: 'ranging', |
|
satellite: 'HST' |
|
} |
|
]; |
|
|
|
initialUAPs.forEach(uap => { |
|
detectedUAPs.push(uap); |
|
addUAPToTable(uap); |
|
addUAPTo3DViewer(uap); |
|
}); |
|
} |
|
|
|
|
|
function startScanner() { |
|
if (scannerActive) return; |
|
|
|
|
|
navigator.mediaDevices.getUserMedia({ video: true }) |
|
.then(function(stream) { |
|
scannerVideo.srcObject = stream; |
|
scannerVideo.style.display = 'block'; |
|
scannerActive = true; |
|
startScannerBtn.classList.add('active'); |
|
|
|
|
|
scanInterval = setInterval(detectUAPs, 100); |
|
}) |
|
.catch(function(err) { |
|
console.error("Error accessing camera: ", err); |
|
alert("Could not access camera. Please ensure you've granted camera permissions."); |
|
}); |
|
} |
|
|
|
|
|
function stopScanner() { |
|
if (!scannerActive) return; |
|
|
|
clearInterval(scanInterval); |
|
const stream = scannerVideo.srcObject; |
|
const tracks = stream.getTracks(); |
|
|
|
tracks.forEach(function(track) { |
|
track.stop(); |
|
}); |
|
|
|
scannerVideo.srcObject = null; |
|
scannerVideo.style.display = 'none'; |
|
scannerActive = false; |
|
startScannerBtn.classList.remove('active'); |
|
|
|
|
|
clearUAPMarkers(); |
|
} |
|
|
|
|
|
function detectUAPs() { |
|
if (!scannerActive) return; |
|
|
|
frameCount++; |
|
|
|
|
|
if (frameCount % 30 === 0) { |
|
|
|
if (Math.random() > 0.7) { |
|
const uapId = 'UAP-' + Date.now().toString().slice(-4); |
|
const shapes = ['triangle', 'circle', 'square', 'cylinder', 'chevron', 'tictac']; |
|
const shape = shapes[Math.floor(Math.random() * shapes.length)]; |
|
|
|
|
|
const x = Math.random() * 80 + 10; |
|
const y = Math.random() * 80 + 10; |
|
|
|
|
|
const altitude = Math.random() * 1000; |
|
|
|
|
|
let atmosphere, atmosphereColor; |
|
if (altitude < 12) { |
|
atmosphere = 'Troposphere'; |
|
atmosphereColor = '#3b82f6'; |
|
} else if (altitude < 50) { |
|
atmosphere = 'Stratosphere'; |
|
atmosphereColor = '#10b981'; |
|
} else if (altitude < 85) { |
|
atmosphere = 'Mesosphere'; |
|
atmosphereColor = '#f59e0b'; |
|
} else if (altitude < 600) { |
|
atmosphere = 'Thermosphere'; |
|
atmosphereColor = '#ef4444'; |
|
} else { |
|
atmosphere = 'Exosphere'; |
|
atmosphereColor = '#8b5cf6'; |
|
} |
|
|
|
|
|
const lat = viewerLocation.lat + (Math.random() * 0.2 - 0.1); |
|
const long = viewerLocation.long + (Math.random() * 0.2 - 0.1); |
|
|
|
|
|
const uap = { |
|
id: uapId, |
|
shape: shape, |
|
x: x, |
|
y: y, |
|
lat: lat, |
|
long: long, |
|
altitude: altitude.toFixed(2), |
|
atmosphere: atmosphere, |
|
atmosphereColor: atmosphereColor, |
|
velocity: (Math.random() * 5000 + 500).toFixed(0) + ' km/h', |
|
timestamp: new Date().toLocaleTimeString(), |
|
technique: techniqueSelect.value, |
|
satellite: satelliteSelect.value |
|
}; |
|
|
|
detectedUAPs.push(uap); |
|
addUAPMarker(uap); |
|
addUAPToTable(uap); |
|
addUAPTo3DViewer(uap); |
|
|
|
|
|
scannerCoords.textContent = `Lat: ${lat.toFixed(4)}° | Long: ${long.toFixed(4)}° | Alt: ${altitude.toFixed(2)}km | ${atmosphere}`; |
|
} |
|
} |
|
|
|
|
|
detectedUAPs.forEach(uap => { |
|
|
|
uap.x += (Math.random() - 0.5) * 0.5; |
|
uap.y += (Math.random() - 0.5) * 0.5; |
|
|
|
|
|
const marker = document.querySelector(`.uap-marker[data-id="${uap.id}"]`); |
|
if (marker) { |
|
marker.style.left = `${uap.x}%`; |
|
marker.style.top = `${uap.y}%`; |
|
} |
|
|
|
|
|
updateUAPIn3DViewer(uap); |
|
}); |
|
} |
|
|
|
|
|
function addUAPMarker(uap) { |
|
const marker = document.createElement('div'); |
|
marker.className = 'uap-marker'; |
|
marker.dataset.id = uap.id; |
|
marker.style.left = `${uap.x}%`; |
|
marker.style.top = `${uap.y}%`; |
|
marker.style.backgroundColor = uap.atmosphereColor; |
|
marker.style.boxShadow = `0 0 10px ${uap.atmosphereColor}`; |
|
|
|
|
|
const info = document.createElement('div'); |
|
info.className = 'uap-info'; |
|
info.innerHTML = ` |
|
<strong>${uap.id}</strong><br> |
|
Shape: ${uap.shape}<br> |
|
Alt: ${uap.altitude}km<br> |
|
${uap.atmosphere} |
|
`; |
|
marker.appendChild(info); |
|
|
|
|
|
marker.addEventListener('mouseenter', () => { |
|
info.style.display = 'block'; |
|
}); |
|
|
|
marker.addEventListener('mouseleave', () => { |
|
info.style.display = 'none'; |
|
}); |
|
|
|
scannerWindow.appendChild(marker); |
|
} |
|
|
|
|
|
function clearUAPMarkers() { |
|
document.querySelectorAll('.uap-marker').forEach(marker => { |
|
marker.remove(); |
|
}); |
|
} |
|
|
|
|
|
function addUAPToTable(uap) { |
|
const row = document.createElement('tr'); |
|
row.className = 'hover:bg-slate-700/50'; |
|
row.innerHTML = ` |
|
<td class="px-4 py-2 whitespace-nowrap text-sm font-medium text-white">${uap.id}</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300">${uap.shape}</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300">${uap.lat.toFixed(4)}°, ${uap.long.toFixed(4)}°</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300">${uap.altitude}km</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300"> |
|
<span class="inline-block w-3 h-3 rounded-full mr-1" style="background-color: ${uap.atmosphereColor}"></span> |
|
${uap.atmosphere} |
|
</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300">${uap.velocity}</td> |
|
<td class="px-4 py-2 whitespace-nowrap text-sm text-slate-300"> |
|
<button class="text-blue-400 hover:text-blue-200 mr-2" onclick="focusUAP('${uap.id}')"> |
|
<i class="fas fa-search"></i> |
|
</button> |
|
<button class="text-red-400 hover:text-red-200" onclick="removeUAP('${uap.id}')"> |
|
<i class="fas fa-trash"></i> |
|
</button> |
|
</td> |
|
`; |
|
uapTableBody.appendChild(row); |
|
} |
|
|
|
|
|
function addUAPTo3DViewer(uap) { |
|
|
|
const scaledAltitude = parseFloat(uap.altitude) / 1000 * 15 + 15; |
|
|
|
|
|
const phi = (90 - uap.lat) * (Math.PI / 180); |
|
const theta = (uap.long + 180) * (Math.PI / 180); |
|
|
|
const x = scaledAltitude * Math.sin(phi) * Math.cos(theta); |
|
const y = scaledAltitude * Math.cos(phi); |
|
const z = scaledAltitude * Math.sin(phi) * Math.sin(theta); |
|
|
|
|
|
let geometry, material; |
|
|
|
switch(uap.shape) { |
|
case 'triangle': |
|
geometry = new THREE.ConeGeometry(0.5, 1, 3); |
|
break; |
|
case 'circle': |
|
geometry = new THREE.SphereGeometry(0.5); |
|
break; |
|
case 'square': |
|
geometry = new THREE.BoxGeometry(0.8, 0.8, 0.8); |
|
break; |
|
case 'cylinder': |
|
geometry = new THREE.CylinderGeometry(0.4, 0.4, 1, 32); |
|
break; |
|
case 'chevron': |
|
|
|
const chevronShape = new THREE.Shape(); |
|
chevronShape.moveTo(-0.5, 0.5); |
|
chevronShape.lineTo(0, -0.5); |
|
chevronShape.lineTo(0.5, 0.5); |
|
geometry = new THREE.ExtrudeGeometry(chevronShape, { |
|
depth: 0.2, |
|
bevelEnabled: false |
|
}); |
|
break; |
|
case 'tictac': |
|
geometry = new THREE.CapsuleGeometry(0.3, 1, 4, 8); |
|
break; |
|
default: |
|
geometry = new THREE.SphereGeometry(0.5); |
|
} |
|
|
|
material = new THREE.MeshPhongMaterial({ |
|
color: new THREE.Color(uap.atmosphereColor), |
|
emissive: new THREE.Color(uap.atmosphereColor), |
|
emissiveIntensity: 0.5, |
|
specular: 0x111111, |
|
shininess: 30 |
|
}); |
|
|
|
const uapObject = new THREE.Mesh(geometry, material); |
|
uapObject.position.set(x, y, z); |
|
uapObject.userData.uapId = uap.id; |
|
|
|
|
|
uapObject.lookAt(0, 0, 0); |
|
|
|
|
|
scene.add(uapObject); |
|
|
|
|
|
uapObjects.push({ |
|
id: uap.id, |
|
object: uapObject |
|
}); |
|
} |
|
|
|
|
|
function updateUAPIn3DViewer(uap) { |
|
const uapObj = uapObjects.find(obj => obj.id === uap.id); |
|
if (!uapObj) return; |
|
|
|
|
|
const scaledAltitude = parseFloat(uap.altitude) / 1000 * 15 + 15; |
|
|
|
|
|
const phi = (90 - uap.lat) * (Math.PI / 180); |
|
const theta = (uap.long + 180) * (Math.PI / 180); |
|
|
|
const x = scaledAltitude * Math.sin(phi) * Math.cos(theta); |
|
const y = scaledAltitude * Math.cos(phi); |
|
const z = scaledAltitude * Math.sin(phi) * Math.sin(theta); |
|
|
|
|
|
uapObj.object.position.set(x, y, z); |
|
|
|
|
|
uapObj.object.lookAt(0, 0, 0); |
|
} |
|
|
|
|
|
function captureUAP() { |
|
if (!scannerActive || detectedUAPs.length === 0) { |
|
alert("No UAPs detected to capture!"); |
|
return; |
|
} |
|
|
|
|
|
const uap = detectedUAPs[detectedUAPs.length - 1]; |
|
|
|
|
|
|
|
alert(`Captured UAP ${uap.id}\nShape: ${uap.shape}\nCoordinates: ${uap.lat.toFixed(4)}°, ${uap.long.toFixed(4)}°\nAltitude: ${uap.altitude}km (${uap.atmosphere})`); |
|
|
|
|
|
const rows = uapTableBody.querySelectorAll('tr'); |
|
rows[rows.length - 1].classList.add('bg-blue-900/30'); |
|
setTimeout(() => { |
|
rows[rows.length - 1].classList.remove('bg-blue-900/30'); |
|
}, 2000); |
|
} |
|
|
|
|
|
function resetView() { |
|
camera.position.set(0, 0, 50); |
|
camera.lookAt(0, 0, 0); |
|
controls.target.set(0, 0, 0); |
|
} |
|
|
|
|
|
function toggleOrbitControls() { |
|
orbitEnabled = !orbitEnabled; |
|
controls.enabled = orbitEnabled; |
|
toggleOrbitBtn.classList.toggle('active'); |
|
} |
|
|
|
|
|
window.focusUAP = function(uapId) { |
|
const uap = detectedUAPs.find(u => u.id === uapId); |
|
if (!uap) return; |
|
|
|
const uapObj = uapObjects.find(obj => obj.id === uapId); |
|
if (!uapObj) return; |
|
|
|
|
|
const targetPosition = uapObj.object.position.clone(); |
|
const cameraPosition = targetPosition.clone().multiplyScalar(1.5); |
|
|
|
|
|
gsap.to(camera.position, { |
|
x: cameraPosition.x, |
|
y: cameraPosition.y, |
|
z: cameraPosition.z, |
|
duration: 1, |
|
ease: "power2.inOut" |
|
}); |
|
|
|
gsap.to(controls.target, { |
|
x: targetPosition.x, |
|
y: targetPosition.y, |
|
z: targetPosition.z, |
|
duration: 1, |
|
ease: "power2.inOut" |
|
}); |
|
|
|
|
|
const rows = uapTableBody.querySelectorAll('tr'); |
|
rows.forEach(row => { |
|
if (row.querySelector('td:first-child').textContent === uapId) { |
|
row.classList.add('bg-blue-900/30'); |
|
setTimeout(() => { |
|
row.classList.remove('bg-blue-900/30'); |
|
}, 2000); |
|
} |
|
}); |
|
}; |
|
|
|
|
|
window.removeUAP = function(uapId) { |
|
|
|
detectedUAPs = detectedUAPs.filter(u => u.id !== uapId); |
|
|
|
|
|
const uapObjIndex = uapObjects.findIndex(obj => obj.id === uapId); |
|
if (uapObjIndex !== -1) { |
|
scene.remove(uapObjects[uapObjIndex].object); |
|
uapObjects.splice(uapObjIndex, 1); |
|
} |
|
|
|
|
|
const rows = uapTableBody.querySelectorAll('tr'); |
|
rows.forEach(row => { |
|
if (row.querySelector('td:first-child').textContent === uapId) { |
|
row.remove(); |
|
} |
|
}); |
|
|
|
|
|
const marker = document.querySelector(`.uap-marker[data-id="${uapId}"]`); |
|
if (marker) marker.remove(); |
|
}; |
|
|
|
|
|
function generateQR(title, url) { |
|
const qr = qrcode(0, 'L'); |
|
qr.addData(url); |
|
qr.make(); |
|
|
|
const qrSize = 200; |
|
const qrContainer = document.createElement('div'); |
|
qrContainer.style.position = 'fixed'; |
|
qrContainer.style.top = '50%'; |
|
qrContainer.style.left = '50%'; |
|
qrContainer.style.transform = 'translate(-50%, -50%)'; |
|
qrContainer.style.backgroundColor = 'white'; |
|
qrContainer.style.padding = '20px'; |
|
qrContainer.style.borderRadius = '8px'; |
|
qrContainer.style.zIndex = '1000'; |
|
qrContainer.style.boxShadow = '0 0 20px rgba(0,0,0,0.5)'; |
|
|
|
const qrTitle = document.createElement('h3'); |
|
qrTitle.textContent = title; |
|
qrTitle.style.marginBottom = '10px'; |
|
qrTitle.style.textAlign = 'center'; |
|
qrContainer.appendChild(qrTitle); |
|
|
|
const qrCanvas = qr.createImgTag(4, 0); |
|
qrContainer.innerHTML += qrCanvas; |
|
|
|
const closeBtn = document.createElement('button'); |
|
closeBtn.textContent = 'Close'; |
|
closeBtn.style.display = 'block'; |
|
closeBtn.style.margin = '10px auto 0'; |
|
closeBtn.style.padding = '5px 15px'; |
|
closeBtn.style.backgroundColor = '#3b82f6'; |
|
closeBtn.style.color = 'white'; |
|
closeBtn.style.border = 'none'; |
|
closeBtn.style.borderRadius = '4px'; |
|
closeBtn.style.cursor = 'pointer'; |
|
closeBtn.addEventListener('click', () => { |
|
document.body.removeChild(qrContainer); |
|
}); |
|
qrContainer.appendChild(closeBtn); |
|
|
|
document.body.appendChild(qrContainer); |
|
} |
|
|
|
|
|
initScanner(); |
|
}); |
|
</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=privateuserh/privateuserh-uaphe-vbeta1-04" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |