Spaces:
Running
Running
File size: 11,871 Bytes
c40323b af724e7 3f78240 c40323b 0c57009 c40323b af724e7 0c57009 af724e7 0c57009 af724e7 0c57009 af724e7 c40323b e5c56d3 a58047e c40323b 4bcabcd c40323b 0c57009 c40323b 0c57009 4bcabcd 0c57009 4bcabcd 0c57009 c40323b 4bcabcd c40323b 4bcabcd c40323b 4bcabcd c40323b 4bcabcd c40323b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Coastal Surveillance Simulator</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="app">
<div class="coastal-surveillance-sim">
<div id="header">
<span class="blink" aria-hidden="true"></span>
<h1>Coastal Surveillance Sim</h1>
<span class="sub">// COASTKEEPER - ONEBERRY</span>
<div class="spacer"></div>
<div class="theme-toggle" id="theme-toggle">
<button type="button" class="theme-btn" data-theme-val="light" title="Light theme" aria-label="Light theme">
<svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="8" cy="8" r="3" stroke="currentColor" stroke-width="1.5"/>
<line x1="8" y1="1" x2="8" y2="3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="8" y1="13" x2="8" y2="15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="1" y1="8" x2="3" y2="8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="13" y1="8" x2="15" y2="8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="3.05" y1="3.05" x2="4.46" y2="4.46" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="11.54" y1="11.54" x2="12.95" y2="12.95" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="12.95" y1="3.05" x2="11.54" y2="4.46" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="4.46" y1="11.54" x2="3.05" y2="12.95" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</button>
<button type="button" class="theme-btn" data-theme-val="dark" title="Dark theme" aria-label="Dark theme">
<svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M13.5 10.5A6 6 0 0 1 5.5 2.5a6 6 0 1 0 8 8z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<button type="button" class="theme-btn" data-theme-val="system" title="System theme" aria-label="System theme">
<svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<rect x="1" y="2" width="14" height="10" rx="1.5" stroke="currentColor" stroke-width="1.5"/>
<line x1="5" y1="14" x2="11" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<line x1="8" y1="12" x2="8" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</button>
</div>
</div>
<div id="canvas-wrap">
<svg id="c"></svg>
<div class="dir-bar" role="group" aria-label="Camera rotation direction">
<button type="button" class="dir-btn" id="dir-cw">↻ CW</button>
<button type="button" class="dir-btn" id="dir-ccw">↺ CCW</button>
</div>
<div class="zoom-bar">
<button type="button" class="zoom-btn" id="zoom-out" aria-label="Zoom out">−</button>
<span id="zoom-label" class="zoom-label">100%</span>
<button type="button" class="zoom-btn" id="zoom-in" aria-label="Zoom in">+</button>
</div>
</div>
<div id="panel">
<div class="section">
<div class="section-title">Status</div>
<div class="stats-grid">
<div class="stat">
<div class="lbl" id="st-scan-lbl" title="Full 360°: time for one rotation at current front/back speeds. Front arc only: time for an out-and-back sweep within the front sector.">Scan time</div>
<div id="st-scan" class="val">—</div>
</div>
<div class="stat">
<div class="lbl">Boat dist.</div>
<div id="st-dist" class="val">—</div>
</div>
<div class="stat">
<div class="lbl">Detected</div>
<div id="st-vis" class="val">—</div>
</div>
<div class="stat stat-risk" title="Blind metres ÷ (blind + detected metres) from your last completed in-FOV and out-of-FOV spells. The bar fills only after their combined length reaches a minimum (avoids noisy early readings).">
<div class="lbl">Blind share</div>
<div class="risk-row">
<div id="st-risk" class="val st-risk-val">—</div>
<div class="risk-track">
<div id="st-risk-bar" class="risk-fill"></div>
</div>
</div>
</div>
</div>
<div class="stats-extra">
<div class="stat">
<div class="lbl">Detected dist.</div>
<div id="st-travel" class="val st-sm">—</div>
<div id="st-travel-prev" class="stat-sub">prev: —</div>
</div>
<div class="stat">
<div class="lbl">Blind dist.</div>
<div id="st-blind" class="val st-sm">—</div>
<div id="st-blind-prev" class="stat-sub">prev: —</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">Camera</div>
<div class="section-body">
<div class="ctrl">
<label for="camera-preset">Presets</label>
<select id="camera-preset" class="preset-select" aria-label="Apply a camera preset">
<option value="" selected>—</option>
<option value="vos1">VOS #1</option>
<option value="prop1">Proposal #1</option>
<option value="prop2">Proposal #2</option>
<option value="prop3">Proposal #3</option>
</select>
</div>
<div class="ctrl">
<label id="camera-count-label" class="cam-layout-label">Rig cameras</label>
<div class="cam-layout-bar" role="radiogroup" aria-labelledby="camera-count-label">
<label class="cam-layout-btn cam-count-btn" title="One camera on the panning rig">
<input type="radio" name="camera-count" value="1" checked />
<span class="cam-layout-btn__text">1 camera</span>
</label>
<label class="cam-layout-btn cam-count-btn" title="Two cameras; same pan, offset boresight">
<input type="radio" name="camera-count" value="2" />
<span class="cam-layout-btn__text">2 cameras</span>
</label>
</div>
<p class="toggle-hint">Same rig rotation (front / back arc speeds). Coverage = union of camera FOVs.</p>
</div>
<div class="camera-panel" aria-label="Camera fields of view and mounting offset">
<div class="camera-panel__title">Camera heads</div>
<div class="camera-panel__row camera-panel__row--ref">
<span class="camera-panel__badge" title="Reference boresight for pan">1</span>
<div class="camera-panel__stem">
<div class="camera-panel__field camera-panel__field--cam1-fov">
<label for="input-fov">Cam 1 FOV <span id="val-fov">18</span>°</label>
<input id="input-fov" type="range" min="5" max="90" step="1" value="18" aria-label="Camera 1 field of view in degrees" />
</div>
<div class="camera-panel__field camera-panel__field--reference">
<span class="camera-panel__ref-label">Offset from cam 1</span>
<span class="camera-panel__ref-val" aria-label="Camera 1 offset, fixed reference">0°</span>
</div>
</div>
</div>
<div class="camera-panel__row" id="camera-panel-cam2-row">
<span class="camera-panel__badge" title="Second camera boresight">2</span>
<div class="camera-panel__stem">
<div class="camera-panel__field">
<label for="input-fov-2">Cam 2 FOV <span id="val-fov-2">18</span>°</label>
<input id="input-fov-2" type="range" min="5" max="90" step="1" value="18" aria-label="Camera 2 field of view in degrees" />
</div>
<div class="camera-panel__field">
<label for="input-cam2-offset">Offset from cam 1 <span id="val-cam2-offset">180</span>°</label>
<input id="input-cam2-offset" type="range" min="0" max="360" step="1" value="180" aria-label="bearing offset of camera 2 from camera 1 in degrees" />
</div>
</div>
</div>
</div>
<div class="ctrl">
<label for="input-front-arc">Front arc <span id="val-front-arc">180</span>°</label>
<input id="input-front-arc" type="range" min="10" max="350" step="5" value="180" />
</div>
<div class="ctrl">
<label id="pan-mode-label" class="cam-layout-label">Pan mode</label>
<div class="cam-layout-bar" role="radiogroup" aria-labelledby="pan-mode-label">
<label class="cam-layout-btn pan-mode-btn" title="Continuous 360° rotation: slower in the front sector, faster in the back sector (back speed).">
<input type="radio" name="pan-mode" value="full360" checked />
<span class="cam-layout-btn__text">360° sweep</span>
</label>
<label class="cam-layout-btn pan-mode-btn" title="Stay inside the front arc: reverses at the sector edges. Uses front speed only.">
<input type="radio" name="pan-mode" value="oscillate" />
<span class="cam-layout-btn__text">Front arc</span>
</label>
</div>
<p class="toggle-hint">CW / CCW flips direction; in Front arc mode the rig reverses at sector limits. With 2 cameras, limits keep both boresights inside the front sector when possible.</p>
</div>
<div class="ctrl">
<label for="input-front-speed">Front speed <span id="val-front-speed">6</span>°/s</label>
<input id="input-front-speed" type="range" min="1" max="30" step="1" value="6" />
</div>
<div id="ctrl-back-speed" class="ctrl">
<label for="input-back-speed">Back speed <span id="val-back-speed">60</span>°/s</label>
<input id="input-back-speed" type="range" min="5" max="180" step="1" value="60" aria-label="Back sector rotation speed, degrees per second" />
</div>
</div>
</div>
<div class="section">
<div class="section-title">Boat</div>
<div class="section-body">
<div class="ctrl">
<label for="input-boat-speed">Speed <span id="val-boat-speed">20</span> kt</label>
<input id="input-boat-speed" type="range" min="1" max="60" step="1" value="20" />
</div>
<div class="hint">
Drag <span class="hint-s">S</span> or <span class="hint-e">E</span> anchors on canvas to reposition
trajectory.
</div>
</div>
</div>
</div>
</div>
</div>
<script src="app.js" defer></script>
</body>
</html> |