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"></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>