moon_flash / index.html
AK51's picture
Upload 21 files
2fec9df verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moon Flash - Lunar Impact Visualization</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0a0a1a 0%, #1a1a3a 100%);
color: #fff;
overflow: hidden;
height: 100vh;
height: 100dvh;
overscroll-behavior: none;
}
#container {
position: relative;
width: 100%;
height: 100%;
height: 100dvh;
}
#canvas {
display: block;
width: 100%;
height: 100%;
touch-action: none;
}
#info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 10px;
backdrop-filter: blur(10px);
max-width: 300px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
#info-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
#info-collapse {
width: 34px;
height: 30px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.08);
color: #fff;
cursor: pointer;
line-height: 1;
font-size: 1.1rem;
}
#info-collapse:hover {
background: rgba(255, 255, 255, 0.14);
}
#info-body {
margin-top: 6px;
}
#info.collapsed {
padding: 14px;
max-width: 220px;
}
#info.collapsed #info-body {
display: none;
}
#info h1 {
font-size: 1.5rem;
margin-bottom: 10px;
color: #ffcc00;
}
#info-header h1 {
margin-bottom: 0;
}
#info p {
font-size: 0.9rem;
margin-bottom: 5px;
line-height: 1.5;
}
#grid-toggle {
margin-top: 10px;
width: 100%;
padding: 8px 10px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.08);
color: #fff;
cursor: pointer;
}
#grid-toggle:hover {
background: rgba(255, 255, 255, 0.14);
}
#impact-anim-toggle {
margin-top: 8px;
width: 100%;
padding: 8px 10px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.08);
color: #fff;
cursor: pointer;
}
#impact-anim-toggle:hover {
background: rgba(255, 255, 255, 0.14);
}
#help-toggle {
margin-top: 8px;
width: 100%;
padding: 8px 10px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.15);
background: rgba(255, 255, 255, 0.08);
color: #fff;
cursor: pointer;
}
#help-toggle:hover {
background: rgba(255, 255, 255, 0.14);
}
#details {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 10px;
backdrop-filter: blur(10px);
max-width: 350px;
border: 1px solid rgba(255, 255, 255, 0.1);
display: none;
opacity: 0;
transform: translateY(14px);
transition: opacity 180ms ease, transform 180ms ease;
pointer-events: none;
}
#details.visible {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
#details.bump {
animation: details-bump 180ms ease;
}
@keyframes details-bump {
0% { transform: translateY(0) scale(1); }
45% { transform: translateY(-2px) scale(1.02); }
100% { transform: translateY(0) scale(1); }
}
#details h2 {
font-size: 1.2rem;
margin-bottom: 10px;
color: #ff6b6b;
}
#details p {
font-size: 0.9rem;
margin-bottom: 5px;
}
#close-details {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
color: #fff;
font-size: 1.5rem;
cursor: pointer;
}
#close-details:hover {
color: #ff6b6b;
}
#coord-tooltip {
position: absolute;
left: 0;
top: 0;
transform: translate(-50%, -120%);
background: rgba(0, 0, 0, 0.75);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 8px;
padding: 8px 10px;
font-size: 0.85rem;
pointer-events: none;
white-space: nowrap;
display: none;
}
#help {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.65);
display: none;
align-items: center;
justify-content: center;
padding: 20px;
}
#help-content {
position: relative;
width: min(760px, 95vw);
max-height: min(78vh, 720px);
overflow: auto;
background: rgba(0, 0, 0, 0.85);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 12px;
padding: 18px 20px;
backdrop-filter: blur(10px);
}
#help-content h2 {
font-size: 1.2rem;
margin-bottom: 10px;
color: #ffcc00;
}
#help-content p {
font-size: 0.92rem;
margin-bottom: 10px;
line-height: 1.55;
color: rgba(255, 255, 255, 0.92);
}
#help-content ul {
margin: 0 0 10px 18px;
padding: 0;
line-height: 1.55;
color: rgba(255, 255, 255, 0.92);
}
#help-close {
position: absolute;
top: 10px;
right: 12px;
background: none;
border: none;
color: #fff;
font-size: 1.5rem;
cursor: pointer;
}
#help-close:hover {
color: #ff6b6b;
}
#loading {
position: absolute;
inset: 0;
display: none;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(10px);
z-index: 50;
}
#loading-content {
width: min(520px, 92vw);
background: rgba(0, 0, 0, 0.75);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 12px;
padding: 16px 18px;
}
#loading-title {
font-size: 1.05rem;
color: #ffcc00;
margin-bottom: 10px;
}
#loading-text {
font-size: 0.92rem;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 12px;
line-height: 1.45;
}
#loading-bar-wrap {
height: 10px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 999px;
overflow: hidden;
}
#loading-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, rgba(255, 204, 0, 0.35), rgba(255, 204, 0, 0.95));
}
#loading-bar.indeterminate {
animation: loading-indeterminate 900ms ease-in-out infinite;
}
@keyframes loading-indeterminate {
0% { transform: translateX(-60%); opacity: 0.7; }
50% { transform: translateX(40%); opacity: 1; }
100% { transform: translateX(140%); opacity: 0.7; }
}
@media (max-width: 640px) {
#info {
top: 10px;
left: 10px;
padding: 12px;
max-width: calc(100vw - 20px);
}
#info h1 {
font-size: 1.25rem;
}
#details {
left: 10px;
right: 10px;
bottom: 10px;
max-width: none;
max-height: min(44vh, 380px);
overflow: auto;
}
#help-content {
width: calc(100vw - 24px);
max-height: 82vh;
}
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
<div id="loading" aria-live="polite" aria-label="Loading">
<div id="loading-content">
<div id="loading-title">Loading Moon Model</div>
<div id="loading-text">Starting…</div>
<div id="loading-bar-wrap"><div id="loading-bar"></div></div>
</div>
</div>
<div id="coord-tooltip"></div>
<div id="info">
<div id="info-header">
<h1>Moon Flash</h1>
<button id="info-collapse" type="button"></button>
</div>
<div id="info-body">
<p>Visualizing lunar impact events</p>
<p>Hover over markers for explosions</p>
<p>Click on impact markers for details</p>
<p>Drag to rotate, scroll to zoom</p>
<button id="grid-toggle" type="button">Toggle Lat/Lon Grid</button>
<button id="impact-anim-toggle" type="button">Hide Overlays</button>
<button id="help-toggle" type="button">Help</button>
</div>
</div>
<div id="details">
<button id="close-details">&times;</button>
<h2 id="details-title">Impact Details</h2>
<p id="details-csv-id"></p>
<p id="details-date"></p>
<p id="details-time"></p>
<p id="details-coords"></p>
<p id="details-duration"></p>
<p id="details-observer"></p>
<p id="details-magnitude"></p>
<p id="details-airmass"></p>
<p id="details-altitude"></p>
<p id="details-azimuth"></p>
<p id="details-peak"></p>
<p id="details-classification"></p>
</div>
<div id="help" role="dialog" aria-modal="true" aria-label="Help">
<div id="help-content">
<button id="help-close" type="button">&times;</button>
<h2>Help</h2>
<p>This program visualizes lunar impact flash events on a 3D Moon. Hover an impact to play an animation, and click an impact to see its details.</p>
<p>Data source:</p>
<ul>
<li>Event data comes from NELIOTA (National Observatory of Athens): <b>https://neliota.astro.noa.gr/DataAccess</b> (Event Details pages).</li>
<li>In this project, events are stored locally under <b>data/event-&lt;id&gt;/</b>.</li>
<li>The viewer reads <b>event-&lt;id&gt;.csv</b> (generated from the downloaded HTML pages) to populate the details panel.</li>
</ul>
<p>Verification:</p>
<ul>
<li>Cross-check event coordinates and visibility with <b>https://hdevillepoix.github.io/LIF_Aladin/</b>.</li>
</ul>
<p>Impact marker meaning:</p>
<ul>
<li><b>Color</b> is based on the average of <b>R (mag)</b> and <b>I (mag)</b>: low average magnitude is yellow, high average magnitude is red.</li>
<li><b>Size</b> is based on <b>Duration (sec)</b>: longer duration events render larger markers.</li>
</ul>
<p>Credit: the program is created by Andy Kong</p>
</div>
</div>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<script type="module" src="app.js?v=20260527"></script>
</body>
</html>