TiGa-RCE commited on
Commit
94faee6
·
verified ·
1 Parent(s): adb939d

Fix replay scrolling and return to playback controls

Browse files

Place recording/playback actions ahead of the visual replay, use normal document scrolling for native telemetry, and add focusable return links to the playback row. Verified baseline regression,20 responsive anchor cases, actual wheel scrolling, stepping/scrubbing, existing UI/receipt checks and independent code review. Only HTML and frontend/release hash manifests change. No simulator, native binary, policy, Godot, Swift, auth, storage or visibility changes.

Files changed (3) hide show
  1. FRONTEND_SOURCE.json +5 -5
  2. RELEASE_MANIFEST.json +2 -2
  3. index.html +9 -9
FRONTEND_SOURCE.json CHANGED
@@ -7,8 +7,8 @@
7
  },
8
  "client_sha256": "cfb536dc3903beeafae8f1f883390423fd0a3b328575bb935184ee537022e656",
9
  "identity_note": "The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.",
10
- "local_customization_id": "selected-network-and-agent-tools-v1-20261023",
11
- "output_sha256": "efd22976ddea5e1f3f08989dbdf94c152af1a0b46618a1737d010b8985f980cb",
12
  "packaged_frontend_files": {
13
  "agent-manifest.json": "7187c85327d588cb3b81f5ddf60bae099567a656bcceac8147ecb2227e07f561",
14
  "agent-tools.js": "134b8c511a04671edf2129b7b4f42d2c0399713471feefaaeee542efab7127b8",
@@ -17,11 +17,11 @@
17
  "client.js": "cfb536dc3903beeafae8f1f883390423fd0a3b328575bb935184ee537022e656",
18
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
19
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
20
- "index.html": "efd22976ddea5e1f3f08989dbdf94c152af1a0b46618a1737d010b8985f980cb",
21
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
22
  "track-map.js": "1612b75e95ccbbb2da4a47d8c8bf2ee406e8f40c626475ae2a1c3c19e119a139"
23
  },
24
- "packaged_frontend_sha256": "6d23e304ce5419e3c586855fa7e048161a5be1713676b31522952bc2bfe4b51c",
25
  "packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
26
- "status": "Selected-driver inspection, visible editor feedback, tab navigation and browser-local agent tools"
27
  }
 
7
  },
8
  "client_sha256": "cfb536dc3903beeafae8f1f883390423fd0a3b328575bb935184ee537022e656",
9
  "identity_note": "The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.",
10
+ "local_customization_id": "replay-document-scrolling-v1-20261023",
11
+ "output_sha256": "2ca75bb63f2fd64368c9d58bca51d724b6d177422e0961fb8abbecbf28d61b69",
12
  "packaged_frontend_files": {
13
  "agent-manifest.json": "7187c85327d588cb3b81f5ddf60bae099567a656bcceac8147ecb2227e07f561",
14
  "agent-tools.js": "134b8c511a04671edf2129b7b4f42d2c0399713471feefaaeee542efab7127b8",
 
17
  "client.js": "cfb536dc3903beeafae8f1f883390423fd0a3b328575bb935184ee537022e656",
18
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
19
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
20
+ "index.html": "2ca75bb63f2fd64368c9d58bca51d724b6d177422e0961fb8abbecbf28d61b69",
21
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
22
  "track-map.js": "1612b75e95ccbbb2da4a47d8c8bf2ee406e8f40c626475ae2a1c3c19e119a139"
23
  },
24
+ "packaged_frontend_sha256": "4742169f2e37cf676a10f6f16ce4f829ff21f32aefc33dd652a9a30aa8946d62",
25
  "packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
26
+ "status": "Replay actions before viewer, document-scrolling black box and accessible return to playback"
27
  }
RELEASE_MANIFEST.json CHANGED
@@ -7,7 +7,7 @@
7
  "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
8
  "DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
- "FRONTEND_SOURCE.json": "bc04e810375438c5eddd56a8adeac2e355ac0fee1d17ff8deed6157e7be2452c",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
@@ -69,7 +69,7 @@
69
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
70
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
71
  "hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
72
- "index.html": "efd22976ddea5e1f3f08989dbdf94c152af1a0b46618a1737d010b8985f980cb",
73
  "native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
74
  "native/blackbox-build-receipt.json": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
75
  "native/blackbox-source.tar.gz": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
 
7
  "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
8
  "DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
+ "FRONTEND_SOURCE.json": "7a2c0de24cd3f523a6d271d9435f7a4293ad6fa7344fe509f1e4891659d69ef3",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
 
69
  "help.html": "58959e994a8e4bbd3c70b2a6256cb699ac615cde718c6d0288fabeee909098a2",
70
  "hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
71
  "hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
72
+ "index.html": "2ca75bb63f2fd64368c9d58bca51d724b6d177422e0961fb8abbecbf28d61b69",
73
  "native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
74
  "native/blackbox-build-receipt.json": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
75
  "native/blackbox-source.tar.gz": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
index.html CHANGED
@@ -7,7 +7,7 @@
7
  @media(max-width:1000px){.batch-layout{grid-template-columns:minmax(0,1fr)}.batch-setup{position:static}.quick-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){body{padding:12px}.card{padding:16px}.row{grid-template-columns:minmax(0,1fr)}.quick-steps{grid-template-columns:minmax(0,1fr)}.header-actions{width:100%}.header-actions>*{flex:1;justify-content:center;text-align:center}.lab-header .intro{font-size:15px}.quick-start>summary .hint{display:block;margin-left:18px}.tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px}.tabs button{font-size:14px;padding:9px 7px}.step-actions,.step-summary{padding-left:0}.add-step{grid-template-columns:minmax(0,1fr)}.batch-setup{padding:14px}.recipe-actions>*{flex:1}.reward{grid-template-columns:minmax(0,1fr) minmax(85px,.7fr) 65px 44px}.reward input{width:65px}.recipe-panel{padding:12px}}
8
  .replay-bar{background:#101d2c;border:1px solid #2a3d52;border-radius:11px;padding:10px 12px;margin:10px 0}.replay-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.replay-row button{min-height:36px;padding:6px 11px;font-size:13px;font-weight:650}.replay-row select{width:auto;min-height:36px;padding:5px 9px;font-size:13px}.replay-row input[type=range]{flex:1;min-width:120px;accent-color:#62dfb1;padding:0}.replay-time{font:600 12px ui-monospace,SFMono-Regular,monospace;color:#91efc6;white-space:nowrap}.replay-layers{display:flex;gap:6px 12px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid #223447;font-size:12.5px;color:#b9cddd}.replay-layers label{display:inline-flex;align-items:center;gap:5px;margin:0;cursor:pointer}.replay-layers input{margin:0}.kpi-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:12px 0}.kpi-tile{background:#101d2c;border:1px solid #2a3d52;border-radius:10px;padding:10px 12px}.kpi-tile .kpi-label{font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;color:#a2b4c8}.kpi-tile .kpi-val{font:800 19px ui-monospace,SFMono-Regular,monospace;color:#62dfb1;margin-top:3px}.kpi-tile .kpi-sub{font-size:11.5px;color:#8fa6bc;margin-top:2px}.chart-box{background:#09111b;border:1px solid #2a3d52;border-radius:10px;padding:10px;margin:10px 0}.chart-box canvas{max-height:190px;display:block}.subtab-bar{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.subtab-bar button{min-height:36px;padding:6px 12px;font-size:13px;border-radius:18px}.subtab-bar button[aria-pressed=true]{background:#62dfb1;color:#102522;font-weight:700}.editor-visual-grid{display:grid;grid-template-columns:minmax(260px,.85fr) minmax(0,1.35fr);gap:16px;align-items:start;margin:14px 0}@media(max-width:850px){.kpi-strip{grid-template-columns:1fr 1fr}.editor-visual-grid{grid-template-columns:minmax(0,1fr)}}
9
 
10
- .replay-workbench{display:grid;gap:14px;align-items:start}#replay_blackbox{max-height:520px;overflow:auto;padding:12px;border:1px solid #2a3d52;border-radius:10px;min-width:0}#replay_blackbox h3{margin-top:0}#replay_blackbox td,#replay_blackbox th{padding:6px;font-size:12px}#drive.replay-focused>.grid{grid-template-columns:minmax(0,1fr)}#drive.replay-focused>.grid>section:first-child{display:none}#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1.35fr) minmax(320px,1fr)}#drive.replay-focused .map{position:sticky;top:70px}#drive.replay-focused .map canvas{max-height:500px}@media(max-width:850px){#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1fr)}#drive.replay-focused .map{position:static}#replay_blackbox{max-height:400px}}
11
  </style>
12
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
13
  <h2 id="appConfirmTitle">Confirm action</h2>
@@ -50,24 +50,24 @@
50
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
51
  <p><label>Vehicle network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
52
  <p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p class="privacy-note">Uploads are processed for this run. By default, the server copy is deleted after the browser verifies the download.</p><details><summary>Optional repeat download</summary><label class="keep-result"><input id="keepServer" type="checkbox"> Keep this result on the server for up to five minutes so I can download it again</label><p class="privacy-note">This is optional and resets after each run. When bucket auto-save is on, verified receipt must delete the server copy first, so repeat download is disabled. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
53
- </details></section><section class="card"><h2>Visual replay &amp; car black box</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><button type="button" id="replay_focus" aria-pressed="false">Expand replay workspace</button><div class="replay-workbench"><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></div><section id="replay_blackbox" hidden aria-label="Recorded car black box"><h3>Car black box</h3><p id="blackbox_phase" class="hint"></p>
54
- <p class="hint">All values below belong to the selected native sample. Sensor inputs were consumed before physics at the decision tick; vehicle state is captured after physics. Samples are 0.1 seconds apart. Contact events identify intervals, not exact impact ticks; the counter does not count unique crashes.</p>
55
- <details><summary>Recorded vehicle state</summary><div class="table-scroll"><table><thead><tr><th>Vehicle state</th><th>Recorded value</th></tr></thead><tbody id="blackbox_state"></tbody></table></div></details>
56
- <h4>Native control commands</h4><div class="table-scroll"><table><thead><tr><th>Control</th><th>Raw command</th><th>Applied after normalization</th><th>Source</th></tr></thead><tbody id="blackbox_controls"></tbody></table></div>
57
- <details><summary>Inputs consumed by the native network</summary><div class="table-scroll"><table><thead><tr><th>Input index</th><th>Sensor</th><th>Parameters</th><th>Native input value</th></tr></thead><tbody id="blackbox_inputs"></tbody></table></div><p class="hint">These are the input values the policy consumed. Ray inputs are not ray-hit positions. Hidden-layer activations are not recorded.</p></details>
58
- <details><summary>Recorded cumulative reward metrics</summary><p class="hint">Metrics accumulate at native statistics callbacks; they are not instantaneous forces or per-reward contributions.</p><div class="table-scroll"><table><thead><tr><th>Metric</th><th>Recorded cumulative value</th></tr></thead><tbody id="blackbox_metrics"></tbody></table></div></details></section></div><div class="replay-bar" id="replayControls" aria-label="Recorded drive controls">
59
  <div class="replay-row"><button type="button" id="replay_record" disabled>Record selected policy</button><label for="replay_duration" style="margin:0">Length</label><select id="replay_duration"><option value="300" selected>5 seconds</option><option value="900">15 seconds</option></select><button type="button" id="replay_download" disabled>Download recording</button><label for="replay_import">Open recording<input type="file" id="replay_import" accept=".json,application/json" disabled></label></div>
60
  <p id="replay_policy" class="hint">Choose or create a network to record a drive.</p>
61
  <p class="hint">Fresh CPU drive · unchanged weights · 60 Hz physics and decisions · wall-hit and idle elimination off. Recording takes a few seconds; playback runs in your browser.</p>
62
  <p id="replay_status" role="status">No replay recorded. The map shows the selected track and its saved starting point.</p>
63
- <div class="replay-row"><button type="button" id="replay_play" disabled>Play</button><button type="button" id="replay_reset" disabled>Restart</button><button type="button" id="replay_prev" disabled>Previous sample</button><button type="button" id="replay_next" disabled>Next sample</button><input type="range" id="replay_scrub" min="1" max="300" value="1" disabled aria-label="Replay tick scrubber"><span id="replay_time_label" class="replay-time">No recording</span></div>
64
  <div class="replay-row" style="margin-top:8px"><label for="replay_camera" style="margin:0">Camera</label><select id="replay_camera" aria-label="Replay camera mode" disabled><option value="full" selected>Full circuit</option><option value="follow">Follow car</option></select><label for="replay_speed" style="margin:0">Speed</label><select id="replay_speed" aria-label="Replay playback speed" disabled><option value="0.25">0.25×</option><option value="0.5">0.5×</option><option value="1" selected>1×</option><option value="2">2×</option></select></div>
65
  <div class="replay-layers"><label><input type="checkbox" id="replay_layer_outline" checked disabled> Car outline</label><label><input type="checkbox" id="replay_layer_line" checked disabled> Recorded path</label><label><input type="checkbox" id="replay_layer_hud" checked disabled> Recorded telemetry</label></div>
66
  <div class="replay-row"><label><input type="checkbox" id="replay_interpolate" disabled> Smooth pose between measured samples</label><label for="replay_event">Contact / active-state interval</label><select id="replay_event" aria-label="Recorded event interval" disabled><option value="">No recording</option></select></div>
67
 
68
  <p id="replay_readout" style="font-size:16px;font-variant-numeric:tabular-nums" aria-live="off"></p>
69
  <details><summary>What does this recording show?</summary><p>A single fresh CPU drive records native state, raw and normalized control commands, and the exact cached sensor inputs every 0.1 seconds. Physics and policy decisions run at 60 Hz. Playback starts paused and shows measured poses by default; optional pose smoothing only interpolates between adjacent measured samples. It does not simulate the car. Black-box values always remain at an actual recorded sample. Ray-hit positions, skid marks and hidden-layer activations are not recorded. This is a selected-policy CPU replay, including for GPU-trained policies; it is not a recording of the original training population.</p><p>The recording remains in this page until replaced, cleared by a changed selection, or the page is closed. Use Download recording to keep its measured samples.</p></details>
70
- </div><div class="map-legend"><span><i class="terrain asphalt"></i> Asphalt</span><span><i class="terrain dirt"></i> Dirt</span><span><i class="terrain ice"></i> Ice</span><span><i class="terrain start"></i> Start</span></div><p id="mapLegend" class="hint"></p><h2>Run &amp; results</h2><button id="download" disabled>Download result</button> <button id="erase" disabled>Delete server-side job data now</button>
 
 
 
 
 
71
  <p><button id="saveLocal" disabled>Download received result (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
72
  <p>The browser keeps the received result in memory until discarded, replaced by a new run, or this page is closed. It is not saved to browser storage.</p>
73
  <h3 id="runState" role="status" aria-live="polite">READY — no run started</h3>
 
7
  @media(max-width:1000px){.batch-layout{grid-template-columns:minmax(0,1fr)}.batch-setup{position:static}.quick-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){body{padding:12px}.card{padding:16px}.row{grid-template-columns:minmax(0,1fr)}.quick-steps{grid-template-columns:minmax(0,1fr)}.header-actions{width:100%}.header-actions>*{flex:1;justify-content:center;text-align:center}.lab-header .intro{font-size:15px}.quick-start>summary .hint{display:block;margin-left:18px}.tabs{display:grid;grid-template-columns:1fr 1fr;gap:6px}.tabs button{font-size:14px;padding:9px 7px}.step-actions,.step-summary{padding-left:0}.add-step{grid-template-columns:minmax(0,1fr)}.batch-setup{padding:14px}.recipe-actions>*{flex:1}.reward{grid-template-columns:minmax(0,1fr) minmax(85px,.7fr) 65px 44px}.reward input{width:65px}.recipe-panel{padding:12px}}
8
  .replay-bar{background:#101d2c;border:1px solid #2a3d52;border-radius:11px;padding:10px 12px;margin:10px 0}.replay-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.replay-row button{min-height:36px;padding:6px 11px;font-size:13px;font-weight:650}.replay-row select{width:auto;min-height:36px;padding:5px 9px;font-size:13px}.replay-row input[type=range]{flex:1;min-width:120px;accent-color:#62dfb1;padding:0}.replay-time{font:600 12px ui-monospace,SFMono-Regular,monospace;color:#91efc6;white-space:nowrap}.replay-layers{display:flex;gap:6px 12px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px solid #223447;font-size:12.5px;color:#b9cddd}.replay-layers label{display:inline-flex;align-items:center;gap:5px;margin:0;cursor:pointer}.replay-layers input{margin:0}.kpi-strip{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:12px 0}.kpi-tile{background:#101d2c;border:1px solid #2a3d52;border-radius:10px;padding:10px 12px}.kpi-tile .kpi-label{font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;color:#a2b4c8}.kpi-tile .kpi-val{font:800 19px ui-monospace,SFMono-Regular,monospace;color:#62dfb1;margin-top:3px}.kpi-tile .kpi-sub{font-size:11.5px;color:#8fa6bc;margin-top:2px}.chart-box{background:#09111b;border:1px solid #2a3d52;border-radius:10px;padding:10px;margin:10px 0}.chart-box canvas{max-height:190px;display:block}.subtab-bar{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.subtab-bar button{min-height:36px;padding:6px 12px;font-size:13px;border-radius:18px}.subtab-bar button[aria-pressed=true]{background:#62dfb1;color:#102522;font-weight:700}.editor-visual-grid{display:grid;grid-template-columns:minmax(260px,.85fr) minmax(0,1.35fr);gap:16px;align-items:start;margin:14px 0}@media(max-width:850px){.kpi-strip{grid-template-columns:1fr 1fr}.editor-visual-grid{grid-template-columns:minmax(0,1fr)}}
9
 
10
+ .replay-workbench{display:grid;gap:14px;align-items:start}#replayControls,#replay_transport,#replay_blackbox{scroll-margin-top:160px}#replayControls{min-width:0}.replay-row>*{max-width:100%}#replay_blackbox{padding:12px;border:1px solid #2a3d52;border-radius:10px;min-width:0}#replay_blackbox h3{margin-top:0}#replay_blackbox td,#replay_blackbox th{padding:6px;font-size:12px}#drive.replay-focused>.grid{grid-template-columns:minmax(0,1fr)}#drive.replay-focused>.grid>section:first-child{display:none}#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1.35fr) minmax(320px,1fr)}#drive.replay-focused .map{position:sticky;top:70px}#drive.replay-focused .map canvas{max-height:500px}@media(max-width:850px){#drive.replay-focused .replay-workbench{grid-template-columns:minmax(0,1fr)}#drive.replay-focused .map{position:static}}
11
  </style>
12
  <dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
13
  <h2 id="appConfirmTitle">Confirm action</h2>
 
50
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
51
  <p><label>Vehicle network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
52
  <p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p class="privacy-note">Uploads are processed for this run. By default, the server copy is deleted after the browser verifies the download.</p><details><summary>Optional repeat download</summary><label class="keep-result"><input id="keepServer" type="checkbox"> Keep this result on the server for up to five minutes so I can download it again</label><p class="privacy-note">This is optional and resets after each run. When bucket auto-save is on, verified receipt must delete the server copy first, so repeat download is disabled. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
53
+ </details></section><section class="card"><h2>Visual replay &amp; car black box</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><button type="button" id="replay_focus" aria-pressed="false">Expand replay workspace</button><div class="replay-bar" id="replayControls" tabindex="-1" aria-label="Recorded drive controls">
 
 
 
 
 
54
  <div class="replay-row"><button type="button" id="replay_record" disabled>Record selected policy</button><label for="replay_duration" style="margin:0">Length</label><select id="replay_duration"><option value="300" selected>5 seconds</option><option value="900">15 seconds</option></select><button type="button" id="replay_download" disabled>Download recording</button><label for="replay_import">Open recording<input type="file" id="replay_import" accept=".json,application/json" disabled></label></div>
55
  <p id="replay_policy" class="hint">Choose or create a network to record a drive.</p>
56
  <p class="hint">Fresh CPU drive · unchanged weights · 60 Hz physics and decisions · wall-hit and idle elimination off. Recording takes a few seconds; playback runs in your browser.</p>
57
  <p id="replay_status" role="status">No replay recorded. The map shows the selected track and its saved starting point.</p>
58
+ <div class="replay-row" id="replay_transport" role="group" aria-label="Playback controls" tabindex="-1"><button type="button" id="replay_play" disabled>Play</button><button type="button" id="replay_reset" disabled>Restart</button><button type="button" id="replay_prev" disabled>Previous sample</button><button type="button" id="replay_next" disabled>Next sample</button><input type="range" id="replay_scrub" min="1" max="300" value="1" disabled aria-label="Replay tick scrubber"><span id="replay_time_label" class="replay-time">No recording</span></div>
59
  <div class="replay-row" style="margin-top:8px"><label for="replay_camera" style="margin:0">Camera</label><select id="replay_camera" aria-label="Replay camera mode" disabled><option value="full" selected>Full circuit</option><option value="follow">Follow car</option></select><label for="replay_speed" style="margin:0">Speed</label><select id="replay_speed" aria-label="Replay playback speed" disabled><option value="0.25">0.25×</option><option value="0.5">0.5×</option><option value="1" selected>1×</option><option value="2">2×</option></select></div>
60
  <div class="replay-layers"><label><input type="checkbox" id="replay_layer_outline" checked disabled> Car outline</label><label><input type="checkbox" id="replay_layer_line" checked disabled> Recorded path</label><label><input type="checkbox" id="replay_layer_hud" checked disabled> Recorded telemetry</label></div>
61
  <div class="replay-row"><label><input type="checkbox" id="replay_interpolate" disabled> Smooth pose between measured samples</label><label for="replay_event">Contact / active-state interval</label><select id="replay_event" aria-label="Recorded event interval" disabled><option value="">No recording</option></select></div>
62
 
63
  <p id="replay_readout" style="font-size:16px;font-variant-numeric:tabular-nums" aria-live="off"></p>
64
  <details><summary>What does this recording show?</summary><p>A single fresh CPU drive records native state, raw and normalized control commands, and the exact cached sensor inputs every 0.1 seconds. Physics and policy decisions run at 60 Hz. Playback starts paused and shows measured poses by default; optional pose smoothing only interpolates between adjacent measured samples. It does not simulate the car. Black-box values always remain at an actual recorded sample. Ray-hit positions, skid marks and hidden-layer activations are not recorded. This is a selected-policy CPU replay, including for GPU-trained policies; it is not a recording of the original training population.</p><p>The recording remains in this page until replaced, cleared by a changed selection, or the page is closed. Use Download recording to keep its measured samples.</p></details>
65
+ </div><div class="replay-workbench"><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></div><section id="replay_blackbox" tabindex="-1" hidden aria-label="Recorded car black box"><div class="section-heading"><h3>Car black box</h3><a href="#replay_transport">Back to playback</a></div><p id="blackbox_phase" class="hint"></p>
66
+ <p class="hint">All values below belong to the selected native sample. Sensor inputs were consumed before physics at the decision tick; vehicle state is captured after physics. Samples are 0.1 seconds apart. Contact events identify intervals, not exact impact ticks; the counter does not count unique crashes.</p>
67
+ <details><summary>Recorded vehicle state</summary><div class="table-scroll"><table><thead><tr><th>Vehicle state</th><th>Recorded value</th></tr></thead><tbody id="blackbox_state"></tbody></table></div></details>
68
+ <h4>Native control commands</h4><div class="table-scroll"><table><thead><tr><th>Control</th><th>Raw command</th><th>Applied after normalization</th><th>Source</th></tr></thead><tbody id="blackbox_controls"></tbody></table></div>
69
+ <details><summary>Inputs consumed by the native network</summary><div class="table-scroll"><table><thead><tr><th>Input index</th><th>Sensor</th><th>Parameters</th><th>Native input value</th></tr></thead><tbody id="blackbox_inputs"></tbody></table></div><p class="hint">These are the input values the policy consumed. Ray inputs are not ray-hit positions. Hidden-layer activations are not recorded.</p></details>
70
+ <details><summary>Recorded cumulative reward metrics</summary><p class="hint">Metrics accumulate at native statistics callbacks; they are not instantaneous forces or per-reward contributions.</p><div class="table-scroll"><table><thead><tr><th>Metric</th><th>Recorded cumulative value</th></tr></thead><tbody id="blackbox_metrics"></tbody></table></div></details><p><a href="#replay_transport">Back to playback</a></p></section></div><div class="map-legend"><span><i class="terrain asphalt"></i> Asphalt</span><span><i class="terrain dirt"></i> Dirt</span><span><i class="terrain ice"></i> Ice</span><span><i class="terrain start"></i> Start</span></div><p id="mapLegend" class="hint"></p><h2>Run &amp; results</h2><button id="download" disabled>Download result</button> <button id="erase" disabled>Delete server-side job data now</button>
71
  <p><button id="saveLocal" disabled>Download received result (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
72
  <p>The browser keeps the received result in memory until discarded, replaced by a new run, or this page is closed. It is not saved to browser storage.</p>
73
  <h3 id="runState" role="status" aria-live="polite">READY — no run started</h3>