1
0
Fork 0
mirror of https://github.com/imjasonh/droneski synced 2026-07-07 00:33:14 +00:00
droneski/index.html
Jason Hall fe7a8bf438 initial commit
Signed-off-by: Jason Hall <imjasonh@gmail.com>
2026-02-22 11:29:27 -05:00

363 lines
11 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Droneski</title>
<link rel="icon" type="image/gif" href="./drone.png" />
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
background: #000;
}
canvas {
display: block;
}
#hud {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
font-family: "Courier New", monospace;
color: #fff;
z-index: 10;
}
/* Viewfinder reticle */
#reticle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 320px;
height: 220px;
border: 2px solid rgba(255, 255, 255, 0.6);
border-radius: 4px;
transition: border-color 0.5s;
}
#reticle::before,
#reticle::after {
content: "";
position: absolute;
background: rgba(255, 255, 255, 0.4);
}
#reticle::before {
top: 50%;
left: 10%;
right: 10%;
height: 1px;
}
#reticle::after {
left: 50%;
top: 10%;
bottom: 10%;
width: 1px;
}
.reticle-corner {
position: absolute;
width: 16px;
height: 16px;
border-color: #fff;
border-style: solid;
transition: border-color 0.5s;
}
.reticle-corner.tl {
top: -2px;
left: -2px;
border-width: 3px 0 0 3px;
}
.reticle-corner.tr {
top: -2px;
right: -2px;
border-width: 3px 3px 0 0;
}
.reticle-corner.bl {
bottom: -2px;
left: -2px;
border-width: 0 0 3px 3px;
}
.reticle-corner.br {
bottom: -2px;
right: -2px;
border-width: 0 3px 3px 0;
}
#rec {
position: absolute;
top: 20px;
left: 24px;
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: bold;
opacity: 0;
transition: opacity 0.3s;
}
#rec.active {
opacity: 1;
}
#mute-indicator {
position: absolute;
top: 46px;
left: 24px;
font-size: 12px;
opacity: 0;
transition: opacity 0.2s;
color: rgba(255, 255, 255, 0.5);
}
#mute-indicator.visible {
opacity: 1;
}
#mute-indicator.muted {
color: #ffa533;
font-weight: bold;
}
#rec .dot {
width: 10px;
height: 10px;
background: #f33;
border-radius: 50%;
animation: blink 1s infinite;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.3;
}
}
#info-bar {
position: absolute;
bottom: 24px;
left: 24px;
font-size: 12px;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
line-height: 1.6;
opacity: 0.8;
}
#warnings {
position: absolute;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
pointer-events: none;
}
.warning {
font-family: "Courier New", monospace;
font-size: 16px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
padding: 4px 16px;
border-radius: 2px;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
animation: warn-pulse 0.8s infinite;
}
.warning.danger {
color: #ff3333;
}
.warning.caution {
color: #ffaa33;
}
@keyframes warn-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.6;
}
}
#minimap {
position: absolute;
bottom: 60px;
right: 24px;
width: 160px;
height: 200px;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 4px;
overflow: hidden;
background: rgba(0, 0, 0, 0.3);
}
#minimap-canvas {
width: 100%;
height: 100%;
}
#start-screen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.85);
z-index: 100;
pointer-events: all;
cursor: pointer;
}
#start-screen h1 {
font-family: "Courier New", monospace;
font-size: 64px;
color: #fff;
margin-bottom: 8px;
letter-spacing: 4px;
}
#start-screen .subtitle {
font-family: "Courier New", monospace;
font-size: 16px;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 48px;
}
#start-screen .prompt {
font-family: "Courier New", monospace;
font-size: 18px;
color: #fff;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
#start-screen .controls {
font-family: "Courier New", monospace;
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
margin-top: 32px;
text-align: center;
line-height: 1.8;
}
#countdown {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
align-items: center;
justify-content: center;
z-index: 90;
pointer-events: none;
}
#countdown .number {
font-family: "Courier New", monospace;
font-size: 120px;
color: #fff;
font-weight: bold;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.5);
}
#end-screen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.85);
z-index: 100;
pointer-events: all;
cursor: pointer;
}
#end-screen h2 {
font-family: "Courier New", monospace;
font-size: 36px;
color: #fff;
margin-bottom: 24px;
}
#end-screen .breakdown {
font-family: "Courier New", monospace;
font-size: 14px;
color: rgba(255, 255, 255, 0.8);
line-height: 2;
text-align: left;
margin-bottom: 32px;
}
#end-screen .prompt {
font-family: "Courier New", monospace;
font-size: 16px;
color: rgba(255, 255, 255, 0.6);
animation: pulse 2s infinite;
}
</style>
</head>
<body>
<div id="hud">
<div id="reticle">
<div class="reticle-corner tl"></div>
<div class="reticle-corner tr"></div>
<div class="reticle-corner bl"></div>
<div class="reticle-corner br"></div>
</div>
<div id="rec"><span class="dot"></span> REC</div>
<div id="mute-indicator">SOUND [Tab]</div>
<div id="warnings"></div>
<div id="info-bar">
<div id="altitude-info">ALT: 0m</div>
<div id="distance-info">DIST: 0m</div>
<div id="speed-info">SPD: 0 km/h</div>
<div id="progress-info">PROGRESS: 0%</div>
</div>
<div id="minimap">
<canvas id="minimap-canvas" width="160" height="200"></canvas>
</div>
</div>
<div id="start-screen">
<h1>DRONESKI</h1>
<div class="subtitle">FPV Drone Camera Operator</div>
<div class="prompt">Click to start</div>
<div class="controls">
W - Throttle &nbsp;|&nbsp; S - Cut engines<br />
A/D - Roll &nbsp;|&nbsp; Mouse - Pitch &amp; Yaw<br />
Tab - Mute &nbsp;|&nbsp; Keep the skier in frame!
</div>
</div>
<div id="countdown">
<div class="number" id="countdown-number">3</div>
</div>
<div id="end-screen">
<h2>RUN COMPLETE</h2>
<div class="breakdown" id="score-breakdown"></div>
<div class="prompt">Click to restart</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>