Spaces:
Running on Zero
Running on Zero
Add one-click full14 reward selection and enforce catalog maximum
Browse filesPreserve existing reward values/types/order; append missing metrics with manual Add defaults. Unified reward controls for max, duplicate, busy and frozen-evaluation states. Native/worker/training settings and all policies unchanged. Previous revision: db111049b8962b41399fdce87458dcfe5b78240e
- FRONTEND_SOURCE.json +9 -9
- README.md +4 -0
- RELEASE_MANIFEST.json +5 -5
- client.js +2 -1
- help.html +1 -0
- index.html +25 -7
FRONTEND_SOURCE.json
CHANGED
|
@@ -5,25 +5,25 @@
|
|
| 5 |
"source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
|
| 6 |
"source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
|
| 7 |
},
|
| 8 |
-
"client_sha256": "
|
| 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": "aits-
|
| 11 |
-
"output_sha256": "
|
| 12 |
"packaged_frontend_files": {
|
| 13 |
"agent-manifest.json": "7187c85327d588cb3b81f5ddf60bae099567a656bcceac8147ecb2227e07f561",
|
| 14 |
"agent-tools.js": "af4af7d4dab229f5988daf49f630e08879025b37b561a5c93669a6667ab8fdf4",
|
| 15 |
"agents.html": "c2c6889e50056c68c921559ccf95267a541622471e2ccec55099d70989ee8110",
|
| 16 |
"assets/track-atlas.json": "d6168fa2bbcf3e387bae2c61aa4912ad4b556038d2c34adeb4a11716139918ea",
|
| 17 |
-
"client.js": "
|
| 18 |
-
"help.html": "
|
| 19 |
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 20 |
-
"index.html": "
|
| 21 |
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
| 22 |
"track-map.js": "1bbd528a5c593bf630698b5e35f939e86df569c79b668445c9d6155c362a87b0",
|
| 23 |
"track-mask.js": "75b20e989b8d192d32c96dff24c5e6f0bf3fdf5bb53302accbd4fc6884eb09f7"
|
| 24 |
},
|
| 25 |
-
"packaged_frontend_sha256": "
|
| 26 |
"packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
|
| 27 |
-
"parent_local_customization_id": "driving-around-
|
| 28 |
-
"status": "
|
| 29 |
}
|
|
|
|
| 5 |
"source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
|
| 6 |
"source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
|
| 7 |
},
|
| 8 |
+
"client_sha256": "12746c2334f4342ed7e1a3182b085e02f17bc57d41d762f7f1ad612b45c240dd",
|
| 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": "aits-full-reward-selection-20261024",
|
| 11 |
+
"output_sha256": "102f19a9c28397f76595f1a289a221065664635655295a103826b34d65ae95c1",
|
| 12 |
"packaged_frontend_files": {
|
| 13 |
"agent-manifest.json": "7187c85327d588cb3b81f5ddf60bae099567a656bcceac8147ecb2227e07f561",
|
| 14 |
"agent-tools.js": "af4af7d4dab229f5988daf49f630e08879025b37b561a5c93669a6667ab8fdf4",
|
| 15 |
"agents.html": "c2c6889e50056c68c921559ccf95267a541622471e2ccec55099d70989ee8110",
|
| 16 |
"assets/track-atlas.json": "d6168fa2bbcf3e387bae2c61aa4912ad4b556038d2c34adeb4a11716139918ea",
|
| 17 |
+
"client.js": "12746c2334f4342ed7e1a3182b085e02f17bc57d41d762f7f1ad612b45c240dd",
|
| 18 |
+
"help.html": "41c5d99f2e378a16bde25e1c6bc1f7c85031f91414b499e826f6bea712b1f92d",
|
| 19 |
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 20 |
+
"index.html": "102f19a9c28397f76595f1a289a221065664635655295a103826b34d65ae95c1",
|
| 21 |
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
| 22 |
"track-map.js": "1bbd528a5c593bf630698b5e35f939e86df569c79b668445c9d6155c362a87b0",
|
| 23 |
"track-mask.js": "75b20e989b8d192d32c96dff24c5e6f0bf3fdf5bb53302accbd4fc6884eb09f7"
|
| 24 |
},
|
| 25 |
+
"packaged_frontend_sha256": "8988293c4cf333b6b4bdf50666cf7c3f155fccff35a3b9e7eb00367e4e8b2a91",
|
| 26 |
"packaged_frontend_sha256_format": "SHA-256 of UTF-8 JSON for packaged_frontend_files, sorted keys, compact separators, no trailing newline",
|
| 27 |
+
"parent_local_customization_id": "aits-driving-around-repository-rename-20261024",
|
| 28 |
+
"status": "Explicit full-catalog reward selection with14metric maximum and unified busy/evaluation controls. Existing reward values and backend/native semantics preserved; qualification recorded separately."
|
| 29 |
}
|
README.md
CHANGED
|
@@ -49,6 +49,10 @@ Recipes and batches are saved in this browser by default. After connecting an ex
|
|
| 49 |
|
| 50 |
The packaged worker supports Formula, Rally, Snowmobile, and Truck. Networks can use up to 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, and 16 neurons per hidden layer. Formula, Rally, and Truck support up to five outputs; Snowmobile supports up to four and cannot use Handbrake. Fresh networks for every vehicle require Steering and Acceleration. Formula imports retain previously supported ordered output subsets; Rally, Snowmobile, and Truck imports must include Steering and Acceleration and follow their vehicle-specific output rules. Supported sensors use original-game defaults when optional parameters are omitted. These are the vanilla worker limits, not support for arbitrary modified-game networks. See [TRACK_LIBRARY.md](TRACK_LIBRARY.md) for track scope and provenance, and [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for result interpretation.
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
## Visual replay and debugging
|
| 53 |
|
| 54 |
Record a selected policy for 5 or 15 seconds, then play, pause, scrub, or step through actual native samples. The car black box shows measured motion, contacts, boost, raw/applied controls and the sensor inputs consumed by the policy at its recorded decision tick. Playback starts paused, the camera is manual, and optional pose smoothing does not interpolate telemetry. Recordings can be downloaded and reopened. A GPU-trained policy is replayed in a fresh CPU evaluation; this is separate from its original training generation. See [REPLAY_BLACKBOX.md](REPLAY_BLACKBOX.md) for capture phases and limits.
|
|
|
|
| 49 |
|
| 50 |
The packaged worker supports Formula, Rally, Snowmobile, and Truck. Networks can use up to 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, and 16 neurons per hidden layer. Formula, Rally, and Truck support up to five outputs; Snowmobile supports up to four and cannot use Handbrake. Fresh networks for every vehicle require Steering and Acceleration. Formula imports retain previously supported ordered output subsets; Rally, Snowmobile, and Truck imports must include Steering and Acceleration and follow their vehicle-specific output rules. Supported sensors use original-game defaults when optional parameters are omitted. These are the vanilla worker limits, not support for arbitrary modified-game networks. See [TRACK_LIBRARY.md](TRACK_LIBRARY.md) for track scope and provenance, and [WINNERS_AND_EVALUATION.md](WINNERS_AND_EVALUATION.md) for result interpretation.
|
| 51 |
|
| 52 |
+
## Reward selection
|
| 53 |
+
|
| 54 |
+
Select any of the 14 supported reward metrics, or use **Add all 14 metrics** to add the complete set at once. The counter shows the selected distinct metrics and disables Add at the catalog maximum. Existing rows, weights and aggregation choices are preserved; newly added metrics use the same default aggregation and +1 weight as **Add reward**. Adjust weights and signs before training. Duplicate metrics must be corrected before adding all, saving or running. The five-row center preset is an example mix, not a reward limit.
|
| 55 |
+
|
| 56 |
## Visual replay and debugging
|
| 57 |
|
| 58 |
Record a selected policy for 5 or 15 seconds, then play, pause, scrub, or step through actual native samples. The car black box shows measured motion, contacts, boost, raw/applied controls and the sensor inputs consumed by the policy at its recorded decision tick. Playback starts paused, the camera is manual, and optional pose smoothing does not interpolate telemetry. Recordings can be downloaded and reopened. A GPU-trained policy is replayed in a fresh CPU evaluation; this is separate from its original training generation. See [REPLAY_BLACKBOX.md](REPLAY_BLACKBOX.md) for capture phases and limits.
|
RELEASE_MANIFEST.json
CHANGED
|
@@ -7,11 +7,11 @@
|
|
| 7 |
"CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
|
| 8 |
"DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
|
| 9 |
"FEEDBACK.md": "ad6d3f9f16ca1d85ac61e762b549de64c657be0d758300391b12d474bdbedbde",
|
| 10 |
-
"FRONTEND_SOURCE.json": "
|
| 11 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 12 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 13 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 14 |
-
"README.md": "
|
| 15 |
"REPLAY_BLACKBOX.md": "a94c6b7e13273535746f63666254a359ef1dc18908711b8a4a33f2bf92dd82a8",
|
| 16 |
"STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
|
| 17 |
"TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
|
|
@@ -65,13 +65,13 @@
|
|
| 65 |
"builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 66 |
"builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 67 |
"builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 68 |
-
"client.js": "
|
| 69 |
"delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
|
| 70 |
"gpu_tickets.py": "20928fcf1ca24648809ad8712c929377bdcc8b5e6b4387bfff3503ec5711928b",
|
| 71 |
-
"help.html": "
|
| 72 |
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 73 |
"hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
|
| 74 |
-
"index.html": "
|
| 75 |
"native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
|
| 76 |
"native/blackbox-build-receipt.json": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
|
| 77 |
"native/blackbox-source.tar.gz": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
|
|
|
|
| 7 |
"CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
|
| 8 |
"DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
|
| 9 |
"FEEDBACK.md": "ad6d3f9f16ca1d85ac61e762b549de64c657be0d758300391b12d474bdbedbde",
|
| 10 |
+
"FRONTEND_SOURCE.json": "1aded69faceb11b64ac78172d9a4064098b9d3e05ea37a6e31a5d3e3d3f3f7f7",
|
| 11 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 12 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 13 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 14 |
+
"README.md": "09f07538a4b0c32fa0c59f5c6d8c4f620f29f7d5001b93c79d71e10c87e01a35",
|
| 15 |
"REPLAY_BLACKBOX.md": "a94c6b7e13273535746f63666254a359ef1dc18908711b8a4a33f2bf92dd82a8",
|
| 16 |
"STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
|
| 17 |
"TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
|
|
|
|
| 65 |
"builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 66 |
"builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 67 |
"builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 68 |
+
"client.js": "12746c2334f4342ed7e1a3182b085e02f17bc57d41d762f7f1ad612b45c240dd",
|
| 69 |
"delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
|
| 70 |
"gpu_tickets.py": "20928fcf1ca24648809ad8712c929377bdcc8b5e6b4387bfff3503ec5711928b",
|
| 71 |
+
"help.html": "41c5d99f2e378a16bde25e1c6bc1f7c85031f91414b499e826f6bea712b1f92d",
|
| 72 |
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 73 |
"hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
|
| 74 |
+
"index.html": "102f19a9c28397f76595f1a289a221065664635655295a103826b34d65ae95c1",
|
| 75 |
"native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
|
| 76 |
"native/blackbox-build-receipt.json": "de3eea6c45a5ae4897287a97b0e2822fdae552a0655250bf940cef20d9b60d96",
|
| 77 |
"native/blackbox-source.tar.gz": "56b43430c68b95bf7ac0d8312975c366c920f99b1653d790fb15b59453728e28",
|
client.js
CHANGED
|
@@ -189,10 +189,11 @@ function openReplayWorkspace({focusRecord=false}={}){
|
|
| 189 |
target.tabIndex=-1;target.scrollIntoView({block:'start'});target.focus({preventScroll:true});
|
| 190 |
}
|
| 191 |
if($('result_replay'))$('result_replay').onclick=()=>openReplayWorkspace({focusRecord:true});
|
| 192 |
-
const trainingOnlyControls=['population','generations','mutation','mutation_end','schedule','adaptive_mutation','selection','parents','elite','crossover','decay','preset'
|
| 193 |
function syncRunModeUI(unavailable=busy||bundleRestoring||bucketOperation){
|
| 194 |
const evaluation=$('run_mode')?.value==='evaluate';
|
| 195 |
for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
|
|
|
|
| 196 |
if($('native_settings'))$('native_settings').hidden=evaluation;
|
| 197 |
if($('reward_settings'))$('reward_settings').hidden=evaluation;
|
| 198 |
if($('freeze_settings'))$('freeze_settings').hidden=evaluation;
|
|
|
|
| 189 |
target.tabIndex=-1;target.scrollIntoView({block:'start'});target.focus({preventScroll:true});
|
| 190 |
}
|
| 191 |
if($('result_replay'))$('result_replay').onclick=()=>openReplayWorkspace({focusRecord:true});
|
| 192 |
+
const trainingOnlyControls=['population','generations','mutation','mutation_end','schedule','adaptive_mutation','selection','parents','elite','crossover','decay','preset'];
|
| 193 |
function syncRunModeUI(unavailable=busy||bundleRestoring||bucketOperation){
|
| 194 |
const evaluation=$('run_mode')?.value==='evaluate';
|
| 195 |
for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
|
| 196 |
+
window.setRewardControlsBusy?.(unavailable||evaluation);
|
| 197 |
if($('native_settings'))$('native_settings').hidden=evaluation;
|
| 198 |
if($('reward_settings'))$('reward_settings').hidden=evaluation;
|
| 199 |
if($('freeze_settings'))$('freeze_settings').hidden=evaluation;
|
help.html
CHANGED
|
@@ -114,6 +114,7 @@
|
|
| 114 |
<p class="small">These checks are bounded predictions for replica conditions, not original-game awards or Steam leaderboard results.</p>
|
| 115 |
</section>
|
| 116 |
|
|
|
|
| 117 |
<section class="section" id="suggested-line"><h2>Compare the recorded drive with a suggested route</h2><p>On Run & results, use <strong>Calculate suggested route</strong>. Dashed yellow shows the mask-derived suggestion and green is the recorded car path. Road shape comes from the native part polygons. Dark shapes show static walls. Record or open a drive, then play, scrub or step through its measured car positions and black box.</p><p>The suggestion searches an 8-unit mask derived from native part polygons, preserves connected openings through split lanes, then checks every final segment for a 32 game-unit static wall margin. It does not model vehicle size, grip, braking or boost, so it is not a fastest-lap prediction or a guarantee that the car can follow it. Distance to the suggestion is a geometric measurement, not a driving score. Broken or infeasible routes report unavailable. This calculation runs in your browser and does not train or simulate a car.</p></section>
|
| 118 |
<section class="section" id="freeze">
|
| 119 |
<h2>Selective freezing</h2>
|
|
|
|
| 114 |
<p class="small">These checks are bounded predictions for replica conditions, not original-game awards or Steam leaderboard results.</p>
|
| 115 |
</section>
|
| 116 |
|
| 117 |
+
<section class="section" id="all-rewards"><h2>Select the full reward set</h2><p>Training & recipes supports all 14 distinct reward metrics at once. Use <strong>Add all 14 metrics</strong> to add missing metrics without replacing existing weights, aggregation choices or row order. New metrics start with the same default aggregation and +1 weight as Add reward; review the signs and weights before training. The counter shows the selected distinct metrics, and Add stops at the supported maximum. If a metric appears twice, correct or remove the duplicate first.</p><p>The five-row center preset is one example mix. You can extend it to the full set. Reward editing is disabled during a run or frozen evaluation.</p></section>
|
| 118 |
<section class="section" id="suggested-line"><h2>Compare the recorded drive with a suggested route</h2><p>On Run & results, use <strong>Calculate suggested route</strong>. Dashed yellow shows the mask-derived suggestion and green is the recorded car path. Road shape comes from the native part polygons. Dark shapes show static walls. Record or open a drive, then play, scrub or step through its measured car positions and black box.</p><p>The suggestion searches an 8-unit mask derived from native part polygons, preserves connected openings through split lanes, then checks every final segment for a 32 game-unit static wall margin. It does not model vehicle size, grip, braking or boost, so it is not a fastest-lap prediction or a guarantee that the car can follow it. Distance to the suggestion is a geometric measurement, not a driving score. Broken or infeasible routes report unavailable. This calculation runs in your browser and does not train or simulate a car.</p></section>
|
| 119 |
<section class="section" id="freeze">
|
| 120 |
<h2>Selective freezing</h2>
|
index.html
CHANGED
|
@@ -333,7 +333,7 @@
|
|
| 333 |
<details id="freeze_settings"><summary>Selective freezing · optional</summary><p class="hint">Keep selected sensor inputs, hidden layers, or output controls unchanged while training. Choices follow the selected network and are saved with recipes. Frozen evaluation always uses an empty freeze selection.</p><div id="freeze_status" class="hint" role="status">Select a network to choose components.</div><div id="freeze_controls" class="row"></div></details>
|
| 334 |
<details id="reward_settings"><summary>Rewards · presets and up to fourteen metrics</summary>
|
| 335 |
<label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
|
| 336 |
-
<div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%.
|
| 337 |
</details></div>
|
| 338 |
<details id="run_settings"><summary>Run settings · timing and elimination</summary><div class="row"><div><span class="hint">Fixed simulation timing</span><input id="control_hz" type="hidden" value="60"><output class="fixed-rate" id="fixed_timing">60 Hz physics · 60 Hz decisions<br>One controller update on every physics tick. Fixed for every new run.</output></div><div><label for="workers">Parallel simulations</label><select id="workers" disabled><option>1</option><option selected>1</option><option>2</option><option>3</option><option>4</option></select></div></div><small>Physics runs at 60 Hz. CPU jobs can use 1–4 worker threads.</small><div id="seed_group"><label for="seed">Random seed</label><input id="seed" type="number" min="0" max="2147483647" value="42105" disabled></div><label><input id="collision" type="checkbox" disabled> Eliminate on wall contact</label><label><input id="idle" type="checkbox" disabled> Eliminate when stuck</label><label for="clean_min_laps">Minimum forward laps for a clean-lap winner</label><input id="clean_min_laps" type="number" min="1" max="100" value="2"><small>Winner classification only. Zero physical contacts are required. This does not change your reward recipe.</small></details></div></div></section>
|
| 339 |
<section id="batch" class="pane" role="tabpanel" aria-labelledby="tab-batch" hidden><div class="card"><div class="section-heading"><h2>Training batches</h2><a href="/help#batches" target="_blank" rel="noopener">How batches work ↗</a></div><p class="section-intro">Arrange saved recipes into a sequence of up to 20 training steps. Use the same recipe more than once to keep training with those settings.</p><div class="batch-layout"><div>
|
|
@@ -535,7 +535,7 @@
|
|
| 535 |
})(typeof window!=='undefined'?window:globalThis);
|
| 536 |
</script><script>(() => {
|
| 537 |
const q=id=>document.getElementById(id),api=window.RecipeLibrary;
|
| 538 |
-
let refreshWorkspace=()=>{},libraryBusy=false;
|
| 539 |
const message=text=>{q('recipe_feedback').textContent=text;q('batches_feedback').textContent=text;};
|
| 540 |
const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
|
| 541 |
const booleans=['adaptive_mutation','collision','idle'];
|
|
@@ -567,6 +567,18 @@
|
|
| 567 |
window.setFreezeNetwork=network=>{freezeNetwork=network?{shape:[...network.NeuralNetwork.Shape],sensors:network.Sensors.map(x=>({...x})),outputs:[...network.Outputs]}:null;renderFreeze();};
|
| 568 |
q('freeze_controls').addEventListener('change',event=>{const input=event.target;if(!input.matches('input[data-freeze-kind]'))return;const kind=input.dataset.freezeKind,id=Number(input.value);selectedFreeze[kind]=input.checked?[...selectedFreeze[kind],id].sort((a,b)=>a-b):selectedFreeze[kind].filter(x=>x!==id);q('preset').value='custom';renderFreeze();});
|
| 569 |
function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 570 |
function rewardRow(r){
|
| 571 |
const row=document.createElement('div');row.className='reward';
|
| 572 |
const metric=document.createElement('select'),type=document.createElement('select'),weight=document.createElement('input'),remove=document.createElement('button');
|
|
@@ -574,10 +586,10 @@
|
|
| 574 |
for(const name of api.metrics)metric.add(new Option(name.replaceAll('_',' '),name));metric.value=r.metric;
|
| 575 |
for(const name of ['default','average'])type.add(new Option(name,name));type.value=r.type;
|
| 576 |
weight.type='number';weight.min=-100;weight.max=100;weight.step=1;weight.value=r.weight;
|
| 577 |
-
const custom=()=>{q('reward_preset').value='custom';};
|
| 578 |
metric.onchange=custom;type.onchange=custom;weight.oninput=custom;
|
| 579 |
remove.textContent='×';remove.setAttribute('aria-label','Remove reward');remove.onclick=()=>{row.remove();custom();};
|
| 580 |
-
row.append(metric,type,weight,remove);q('rewards').append(row);
|
| 581 |
}
|
| 582 |
function currentSettings(){
|
| 583 |
const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
|
|
@@ -606,7 +618,7 @@
|
|
| 606 |
for(const kind of ['layers','inputs','outputs'])selectedFreeze[kind]=[...data.freeze[kind]];renderFreeze();
|
| 607 |
q('recipe_draft').value=JSON.stringify(data,null,2);updateWorkBudget();refreshWorkspace();
|
| 608 |
}
|
| 609 |
-
const editable=[...fields,'training_ticks','
|
| 610 |
for(const id of editable)q(id).disabled=false;
|
| 611 |
q('end_rate_group').hidden=false;
|
| 612 |
const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
|
|
@@ -634,14 +646,20 @@
|
|
| 634 |
window.setTrainingBusy=(settingsBusy,controlsBusy=settingsBusy)=>{
|
| 635 |
libraryBusy=controlsBusy;
|
| 636 |
for(const id of editable)q(id).disabled=settingsBusy;
|
| 637 |
-
|
| 638 |
for(const id of ['recipe_save','recipe_load','recipe_apply_draft','recipe_slot','recipe_name','recipe_import','recipe_clear','batch_save','batch_load','batch_slot','batch_name','batch_recipe_sequence','carry','queue_add','batch_add_recipe'])q(id).disabled=controlsBusy;
|
| 639 |
refreshWorkspace(false);
|
| 640 |
};
|
| 641 |
for(const id of ['population','generations','training_ticks'])q(id).addEventListener('input',updateWorkBudget);
|
| 642 |
q('run_mode')?.addEventListener('change',updateWorkBudget);
|
| 643 |
q('backend')?.addEventListener('change',updateWorkBudget);
|
| 644 |
-
q('add').onclick=()=>{if(q('rewards').children.length>=api.metrics.length)return;const used=rewards().map(r=>r.metric);rewardRow({metric:api.metrics.find(m=>!used.includes(m)),type:'default',weight:1});q('reward_preset').value='custom';};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 645 |
q('reward_preset').onchange=()=>{
|
| 646 |
const key=q('reward_preset').value;if(key==='custom')return;
|
| 647 |
const rows={distance:[['total_score',100]],center:[['total_score',100],['total_distance_from_center',-60],['total_distance_from_wall',10],['collision_count',-100],['best_lap_performance',5]],clean:[['total_score',100],['collision_count',-30]],lap:[['best_lap_performance',100]]};
|
|
|
|
| 333 |
<details id="freeze_settings"><summary>Selective freezing · optional</summary><p class="hint">Keep selected sensor inputs, hidden layers, or output controls unchanged while training. Choices follow the selected network and are saved with recipes. Frozen evaluation always uses an empty freeze selection.</p><div id="freeze_status" class="hint" role="status">Select a network to choose components.</div><div id="freeze_controls" class="row"></div></details>
|
| 334 |
<details id="reward_settings"><summary>Rewards · presets and up to fourteen metrics</summary>
|
| 335 |
<label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
|
| 336 |
+
<div id="rewards"></div><div class="toolbar"><button id="add" type="button" disabled>+ Add reward</button><button id="add_all_rewards" type="button" disabled>Add all 14 metrics</button></div><p id="reward_count" class="hint" role="status" aria-live="polite"></p><small>Weights −100…+100; absolute shares normalize to 100%. One row per metric, up to the full supported catalog. Adding all keeps existing rewards unchanged; new metrics start at +1. Adjust signs and weights for the driving you want to train.</small>
|
| 337 |
</details></div>
|
| 338 |
<details id="run_settings"><summary>Run settings · timing and elimination</summary><div class="row"><div><span class="hint">Fixed simulation timing</span><input id="control_hz" type="hidden" value="60"><output class="fixed-rate" id="fixed_timing">60 Hz physics · 60 Hz decisions<br>One controller update on every physics tick. Fixed for every new run.</output></div><div><label for="workers">Parallel simulations</label><select id="workers" disabled><option>1</option><option selected>1</option><option>2</option><option>3</option><option>4</option></select></div></div><small>Physics runs at 60 Hz. CPU jobs can use 1–4 worker threads.</small><div id="seed_group"><label for="seed">Random seed</label><input id="seed" type="number" min="0" max="2147483647" value="42105" disabled></div><label><input id="collision" type="checkbox" disabled> Eliminate on wall contact</label><label><input id="idle" type="checkbox" disabled> Eliminate when stuck</label><label for="clean_min_laps">Minimum forward laps for a clean-lap winner</label><input id="clean_min_laps" type="number" min="1" max="100" value="2"><small>Winner classification only. Zero physical contacts are required. This does not change your reward recipe.</small></details></div></div></section>
|
| 339 |
<section id="batch" class="pane" role="tabpanel" aria-labelledby="tab-batch" hidden><div class="card"><div class="section-heading"><h2>Training batches</h2><a href="/help#batches" target="_blank" rel="noopener">How batches work ↗</a></div><p class="section-intro">Arrange saved recipes into a sequence of up to 20 training steps. Use the same recipe more than once to keep training with those settings.</p><div class="batch-layout"><div>
|
|
|
|
| 535 |
})(typeof window!=='undefined'?window:globalThis);
|
| 536 |
</script><script>(() => {
|
| 537 |
const q=id=>document.getElementById(id),api=window.RecipeLibrary;
|
| 538 |
+
let refreshWorkspace=()=>{},libraryBusy=false,rewardControlsBusy=false;
|
| 539 |
const message=text=>{q('recipe_feedback').textContent=text;q('batches_feedback').textContent=text;};
|
| 540 |
const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
|
| 541 |
const booleans=['adaptive_mutation','collision','idle'];
|
|
|
|
| 567 |
window.setFreezeNetwork=network=>{freezeNetwork=network?{shape:[...network.NeuralNetwork.Shape],sensors:network.Sensors.map(x=>({...x})),outputs:[...network.Outputs]}:null;renderFreeze();};
|
| 568 |
q('freeze_controls').addEventListener('change',event=>{const input=event.target;if(!input.matches('input[data-freeze-kind]'))return;const kind=input.dataset.freezeKind,id=Number(input.value);selectedFreeze[kind]=input.checked?[...selectedFreeze[kind],id].sort((a,b)=>a-b):selectedFreeze[kind].filter(x=>x!==id);q('preset').value='custom';renderFreeze();});
|
| 569 |
function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
|
| 570 |
+
function syncRewardControls(){
|
| 571 |
+
const rows=rewards(),used=new Set(rows.map(r=>r.metric)),maximum=api.metrics.length;
|
| 572 |
+
const unavailable=rewardControlsBusy||q('run_mode')?.value==='evaluate',duplicates=used.size!==rows.length;
|
| 573 |
+
q('add').disabled=unavailable||rows.length>=maximum;
|
| 574 |
+
q('add_all_rewards').disabled=unavailable||duplicates||rows.length>=maximum;
|
| 575 |
+
q('reward_preset').disabled=unavailable;
|
| 576 |
+
q('add_all_rewards').textContent='Add all '+maximum+' metrics';
|
| 577 |
+
for(const node of q('rewards').querySelectorAll('input,select,button'))node.disabled=unavailable;
|
| 578 |
+
const text=used.size+' / '+maximum+' distinct reward metrics selected. '+(duplicates?'A metric is selected more than once. Choose each metric once before adding all.':used.size===maximum?'All supported metrics are included.':'Add individual rewards or add all remaining metrics at once.');
|
| 579 |
+
if(q('reward_count').textContent!==text)q('reward_count').textContent=text;
|
| 580 |
+
}
|
| 581 |
+
window.setRewardControlsBusy=unavailable=>{rewardControlsBusy=!!unavailable;syncRewardControls();};
|
| 582 |
function rewardRow(r){
|
| 583 |
const row=document.createElement('div');row.className='reward';
|
| 584 |
const metric=document.createElement('select'),type=document.createElement('select'),weight=document.createElement('input'),remove=document.createElement('button');
|
|
|
|
| 586 |
for(const name of api.metrics)metric.add(new Option(name.replaceAll('_',' '),name));metric.value=r.metric;
|
| 587 |
for(const name of ['default','average'])type.add(new Option(name,name));type.value=r.type;
|
| 588 |
weight.type='number';weight.min=-100;weight.max=100;weight.step=1;weight.value=r.weight;
|
| 589 |
+
const custom=()=>{q('reward_preset').value='custom';syncRewardControls();};
|
| 590 |
metric.onchange=custom;type.onchange=custom;weight.oninput=custom;
|
| 591 |
remove.textContent='×';remove.setAttribute('aria-label','Remove reward');remove.onclick=()=>{row.remove();custom();};
|
| 592 |
+
row.append(metric,type,weight,remove);q('rewards').append(row);syncRewardControls();
|
| 593 |
}
|
| 594 |
function currentSettings(){
|
| 595 |
const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
|
|
|
|
| 618 |
for(const kind of ['layers','inputs','outputs'])selectedFreeze[kind]=[...data.freeze[kind]];renderFreeze();
|
| 619 |
q('recipe_draft').value=JSON.stringify(data,null,2);updateWorkBudget();refreshWorkspace();
|
| 620 |
}
|
| 621 |
+
const editable=[...fields,'training_ticks','preset','starter_settings_reset'];
|
| 622 |
for(const id of editable)q(id).disabled=false;
|
| 623 |
q('end_rate_group').hidden=false;
|
| 624 |
const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
|
|
|
|
| 646 |
window.setTrainingBusy=(settingsBusy,controlsBusy=settingsBusy)=>{
|
| 647 |
libraryBusy=controlsBusy;
|
| 648 |
for(const id of editable)q(id).disabled=settingsBusy;
|
| 649 |
+
window.setRewardControlsBusy(settingsBusy);
|
| 650 |
for(const id of ['recipe_save','recipe_load','recipe_apply_draft','recipe_slot','recipe_name','recipe_import','recipe_clear','batch_save','batch_load','batch_slot','batch_name','batch_recipe_sequence','carry','queue_add','batch_add_recipe'])q(id).disabled=controlsBusy;
|
| 651 |
refreshWorkspace(false);
|
| 652 |
};
|
| 653 |
for(const id of ['population','generations','training_ticks'])q(id).addEventListener('input',updateWorkBudget);
|
| 654 |
q('run_mode')?.addEventListener('change',updateWorkBudget);
|
| 655 |
q('backend')?.addEventListener('change',updateWorkBudget);
|
| 656 |
+
q('add').onclick=()=>{if(rewardControlsBusy||q('run_mode')?.value==='evaluate'||q('rewards').children.length>=api.metrics.length)return;const used=rewards().map(r=>r.metric);rewardRow({metric:api.metrics.find(m=>!used.includes(m)),type:'default',weight:1});q('reward_preset').value='custom';};
|
| 657 |
+
q('add_all_rewards').onclick=()=>{
|
| 658 |
+
const rows=rewards(),used=new Set(rows.map(r=>r.metric));
|
| 659 |
+
if(rewardControlsBusy||q('run_mode')?.value==='evaluate'||used.size!==rows.length||rows.length>=api.metrics.length)return;
|
| 660 |
+
for(const metric of api.metrics)if(!used.has(metric))rewardRow({metric,type:'default',weight:1});
|
| 661 |
+
q('reward_preset').value='custom';syncRewardControls();
|
| 662 |
+
};
|
| 663 |
q('reward_preset').onchange=()=>{
|
| 664 |
const key=q('reward_preset').value;if(key==='custom')return;
|
| 665 |
const rows={distance:[['total_score',100]],center:[['total_score',100],['total_distance_from_center',-60],['total_distance_from_wall',10],['collision_count',-100],['best_lap_performance',5]],clean:[['total_score',100],['collision_count',-30]],lap:[['best_lap_performance',100]]};
|