TiGa-RCE commited on
Commit
5a037eb
·
verified ·
1 Parent(s): 54a5f89

Add matched four-vehicle support to ALD training

Browse files

Preserve vehicle Type 0–3 through network import, training and export. Select the packaged trusted vehicle scene, enforce original control-output rules and report vehicle identity for optional global Steam estimates. Keep the existing CPU-private and GPU-protected Space visibility settings and package member boundary unchanged.

BETA_TESTING.md CHANGED
@@ -36,7 +36,7 @@ restricted source repository as the app entry point.
36
 
37
  ## Supported runner contract
38
 
39
- The worker accepts Formula networks with any ordered unique subset of the five game controls: Steering, Acceleration, Handbrake, Brake, and Boost. The vanilla maximum is 20 inputs (up to 13 raycasts and 7 other sensors), 12 total layers, 16 neurons per hidden layer, and 2,869 dense weights and biases, with shape `[20]+[16]*10+[5]`. Networks with fewer outputs and layers remain supported. All 13 game sensor types are accepted, including game defaults for omitted parameter values. This is the bounded vanilla Formula contract; it does not claim support for arbitrary modified-game networks.
40
 
41
  The preview shows tile layout and terrain, not collision geometry. Star challenges are not evaluated.
42
 
 
36
 
37
  ## Supported runner contract
38
 
39
+ The worker preserves Formula (Type 0), Rally (Type 1), Snowmobile (Type 2), and Truck (Type 3) on import, in candidate exports, and in run reports. Formula imports retain legacy ordered output subsets. Fresh networks for all vehicles require Steering and Acceleration; Rally, Snowmobile and Truck imports must also retain those outputs. Snowmobile Handbrake is unavailable in the original editor. Networks allow at most 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, and 16 neurons per hidden layer. The maximum is `[20]+[16]*10+[5]` (2,869 parameters) for Formula, Rally and Truck; Snowmobile has at most four outputs, `[20]+[16]*10+[4]` (2,852 parameters). All 13 game sensor types use original-game defaults for omitted parameters. These are vanilla worker limits, not support for arbitrary modified-game networks.
40
 
41
  The preview shows tile layout and terrain, not collision geometry. Star challenges are not evaluated.
42
 
BINARY_PROVENANCE.json CHANGED
@@ -1,24 +1,72 @@
1
  {
2
- "source_repository": "https://github.com/Zorro909/driving_sim_rs",
3
- "simulator_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
4
- "simulator_source_space": "TiGa-RCE/ald-tao-gpu",
5
- "simulator_source_space_revision": "ba07e35a39211af7a0deda0ebd9adb2c554b4f38",
6
- "source_space_image_config": "sha256:31f7854e5fac0b54679eed2899c8951cd96571650ea6c74c27e2400a8c4aa6d3",
7
- "importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
8
- "ui_refresh_date": "2026-10-12",
9
- "reason": "Current upstream b90b8af GH Actions library is HIP/ROCm and cannot run on NVIDIA ZeroGPU. This matched prior CUDA simulator/library pair supports the current Formula-only worker. The two newer upstream commits add snowmobile GPU support, which this worker does not expose.",
10
- "artifacts": {
11
  "bin/altd-sim": {
12
- "sha256": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
13
- "bytes": 13911800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  },
15
  "bin/libaltd_gpu.so": {
16
- "sha256": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
17
- "bytes": 3933424
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  },
19
  "bin/extract_saved_track": {
20
- "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
21
- "bytes": 3247776
 
 
 
 
22
  }
23
- }
 
 
 
 
 
 
 
 
24
  }
 
1
  {
2
+ "artifact_origins": {
 
 
 
 
 
 
 
 
3
  "bin/altd-sim": {
4
+ "actions_run_id": 38203558700,
5
+ "archive_member": "altd-sim-nightly-x86_64-unknown-linux-gnu/altd-sim",
6
+ "bytes": 15774792,
7
+ "evidence_path": "build/receipts/upstream-altd-sim-nightly-x86_64-unknown-linux-gnu.tar.gz",
8
+ "evidence_sha256": "15ddf3cc8748a13ab123226ed328fb65acfaade08351f97a93686223aa2cceed",
9
+ "origin_type": "github_actions_archive_member",
10
+ "run_conclusion": "success",
11
+ "sha256": "0135ecc3d435a9d327be7a92e048cfb5c5291a02ef1e0dddd6ead1cc19b31166",
12
+ "source_archive_sha256": "15ddf3cc8748a13ab123226ed328fb65acfaade08351f97a93686223aa2cceed",
13
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
14
+ "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
15
+ },
16
+ "bin/extract_saved_track": {
17
+ "build_receipt_path": "cpu/IMPORTER_BUILD_RECEIPT.json",
18
+ "build_receipt_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
19
+ "bytes": 3247776,
20
+ "compatibility_receipt": "build/receipts/build-receipt.json",
21
+ "evidence_path": "cpu/IMPORTER_BUILD_RECEIPT.json",
22
+ "evidence_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
23
+ "origin_type": "retained_verified_importer_binary",
24
+ "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
25
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
26
+ "source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
27
  },
28
  "bin/libaltd_gpu.so": {
29
+ "build_command": "CUDA_ARCH=sm_86,sm_120 OUT=/work/artifacts/gpu bash /work/source/gpu/build-cuda.sh",
30
+ "build_log_path": "build/receipts/cuda-build.log",
31
+ "build_log_sha256": "c4ea4bde35aa972644dd3d6ad7511d097736547ab2afb216920e67b26d954be6",
32
+ "builder_image": "nvidia/cuda:13.0.2-devel-ubuntu22.04",
33
+ "builder_image_digest": "sha256:1c517d4fb96528c8999e14e6e6b16d7e2ff9ae8d194fd788d60fdc88e693e982",
34
+ "bytes": 4711704,
35
+ "compiled_architectures": [
36
+ "sm_86",
37
+ "sm_120",
38
+ "compute_120 PTX"
39
+ ],
40
+ "evidence_path": "build/source-b90b8af.tar.gz",
41
+ "evidence_sha256": "e9e561c6d9c56cedf344aaf9d91f584a4d5730ccd26ac5a2bfa23c3eed9204e6",
42
+ "origin_type": "local_cuda_build",
43
+ "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
44
+ "source_archive_path": "build/source-b90b8af.tar.gz",
45
+ "source_archive_sha256": "e9e561c6d9c56cedf344aaf9d91f584a4d5730ccd26ac5a2bfa23c3eed9204e6",
46
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
47
+ "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
48
+ }
49
+ },
50
+ "artifacts": {
51
+ "bin/altd-sim": {
52
+ "bytes": 15774792,
53
+ "sha256": "0135ecc3d435a9d327be7a92e048cfb5c5291a02ef1e0dddd6ead1cc19b31166"
54
  },
55
  "bin/extract_saved_track": {
56
+ "bytes": 3247776,
57
+ "sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a"
58
+ },
59
+ "bin/libaltd_gpu.so": {
60
+ "bytes": 4711704,
61
+ "sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca"
62
  }
63
+ },
64
+ "build_receipt": "../build/receipts/build-receipt.json",
65
+ "build_receipt_sha256": "789806b8d70b73a718e889fb202171c18b50070e04a70ab57af9b93d0ad58a76",
66
+ "github_actions_run": 38203558700,
67
+ "importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
68
+ "note": "The simulator is the exact b90 Linux Actions artifact; the CUDA library is built from the same b90 source for sm_86 and sm_120 with compute_120 PTX. Rust/C layout ABI validation passed. No CUDA device or kernel execution was available in the local builder; hosted CUDA qualification remains separate. The retained d8 track importer is separately identified and bounded compatibility is linked.",
69
+ "run_conclusion": "success",
70
+ "source_repository": "https://github.com/Zorro909/driving_sim_rs",
71
+ "source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
72
  }
CUDA_REFERENCE.md CHANGED
@@ -1,6 +1,6 @@
1
  # Bounded CPU/CUDA reference check
2
 
3
- This protocol defines a reproducible generated input for qualifying the package's largest vanilla Formula network through the native simulator. A passing run covers only the selected B01 track, fixture, settings, and build. It does not establish broad original-game parity, training quality, or general CPU/CUDA equivalence.
4
 
5
  ## Public-package fixture
6
 
 
1
  # Bounded CPU/CUDA reference check
2
 
3
+ This protocol defines a reproducible generated input for qualifying the package's largest vanilla Formula network through the native simulator. This maximum five-output Formula fixture is one bounded qualification case; separate vehicle-specific runtime checks are required for Rally, Snowmobile and Truck. A passing run covers only the selected B01 track, fixture, settings, and build. It does not establish broad original-game parity, training quality, or general CPU/CUDA equivalence.
4
 
5
  ## Public-package fixture
6
 
DATA_POLICY.md CHANGED
@@ -112,7 +112,7 @@ turn public ephemeral storage into persistent storage.
112
 
113
  ## Optional public Steam leaderboard check
114
 
115
- The “After a completed lap” checkbox is off by default. With it off, or when a run reports no completed lap, the browser makes no leaderboard request. When enabled, the browser sends only the built-in track ID and hash, Formula vehicle type, and reported best-lap seconds to this app's same-origin server. Custom or unidentified tracks are not sent. HF does not forward the lap, network, Steam ID, account credential, file name or other run data to Steam.
116
 
117
  The app reads the public Steam Community track index and matching board XML without a Steam login or publisher key. It resolves exact catalog reference labels against that live index; an absent or ambiguous mapping is unavailable. The app retains only a short-lived in-process cache of public board rank/time rows (up to 60 seconds) and the public index mapping (up to five minutes). Player names, Steam IDs and raw XML are discarded after parsing. The comparison request and result are not stored in the job result store or recipe library.
118
 
 
112
 
113
  ## Optional public Steam leaderboard check
114
 
115
+ The “After a completed lap” checkbox is off by default. With it off, or when a run reports no completed lap, the browser makes no leaderboard request. When enabled, the browser sends only the built-in track ID and hash, reported vehicle type (Formula, Rally, Snowmobile or Truck), and best-lap seconds to this app's same-origin server. Custom or unidentified tracks are not sent. HF does not forward the lap, network, Steam ID, account credential, file name or other run data to Steam.
116
 
117
  The app reads the public Steam Community track index and matching board XML without a Steam login or publisher key. It resolves exact catalog reference labels against that live index; an absent or ambiguous mapping is unavailable. The app retains only a short-lived in-process cache of public board rank/time rows (up to 60 seconds) and the public index mapping (up to five minutes). Player names, Steam IDs and raw XML are discarded after parsing. The comparison request and result are not stored in the job result store or recipe library.
118
 
FRONTEND_SOURCE.json CHANGED
@@ -1,10 +1,10 @@
1
  {
2
  "source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
3
  "source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8",
4
- "output_sha256": "713496757a5fa796cf35eb9fba7a4f29b0eb2f8abdd6c8e3a6fdfd8036a3a30f",
5
  "scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
6
- "status": "Original-game export metadata corrected; optional Steam comparison; vehicle/track audit separate",
7
  "track_atlas_sha256": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
8
- "client_sha256": "93af3e91c0c5fe56ea0d95c40bb26b3e81aff3d36c38b035b4666a4d0955563a",
9
  "track_map_sha256": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"
10
  }
 
1
  {
2
  "source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
3
  "source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8",
4
+ "output_sha256": "ef759a06305e94edb5ed0e49a587db8c39e3833ec2e02a1bec441c0287c385fd",
5
  "scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
6
+ "status": "Four vehicle UI and Type plumbing; native vehicle support pending runtime qualification; optional Steam comparison",
7
  "track_atlas_sha256": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
8
+ "client_sha256": "f227469481a6a393f78636fde214473f54219c8af016050b35c6ef1af86eff34",
9
  "track_map_sha256": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"
10
  }
README.md CHANGED
@@ -8,9 +8,9 @@ hf_oauth: true
8
  hf_oauth_expiration_minutes: 60
9
  ---
10
 
11
- Public GPU app package. Its intended topology is a publicly reachable app at https://tiga-rce-ald-tao-gpu.hf.space/ with the GPU Space source repository restricted; the standalone CPU Space remains private. Deployment status and build-specific qualification are recorded in the release receipt. The native Formula runner uses the matched NVIDIA CUDA simulator/library pair from Zorro909/driving_sim_rs at commit d8ab74c25df70b6a86ed101080e33d5fb785ea6f. The newer b90b8af source was checked, but its published library targets AMD HIP and its added five-wheel snowmobile support is outside this Formula-only package. CPU runs anonymously. GPU is explicitly selected and subject to available HF allowance; optional HF sign-in uses the official OAuth flow and needs no personal token entry.
12
 
13
- The selected track map previews tile layout and asphalt/dirt/ice directly from the selected file. Twenty-eight reconstructed editor-format tracks are included. Settings-only recipes and batches save in the visitor's browser. Formula networks may use any ordered unique subset of the five game controls. Supported networks have at most 20 inputs (13 raycasts plus 7 other sensors), 12 total layers, 16 neurons per hidden layer, and 2,869 dense weights and biases; the largest vanilla shape is `[20]+[16]*10+[5]`. All 13 game sensor types are supported with game defaults for omitted parameters. These limits describe the vanilla Formula worker contract, not unrestricted modified-game networks.
14
 
15
  Application-controlled inputs and intermediate files are temporary. Outputs are held in memory for at most five minutes and deleted sooner after verified download by default; a single-run visitor may explicitly keep the result until that five-minute deadline. This is not a provider-wide zero-data-retention guarantee. Read DATA_POLICY.md and TRACK_LIBRARY.md. Upstream code and license: https://github.com/Zorro909/driving_sim_rs. Open upstream PRs 19 and 21 are not included.
16
 
 
8
  hf_oauth_expiration_minutes: 60
9
  ---
10
 
11
+ Public GPU app package. Its intended topology is a publicly reachable app at https://tiga-rce-ald-tao-gpu.hf.space/ with the GPU Space source repository restricted; the standalone CPU Space remains private. Deployment status and build-specific qualification are recorded in the release receipt. The native runner accepts Formula (Type 0), Rally (Type 1), Snowmobile (Type 2), and Truck (Type 3) networks and selects a packaged trusted scene template from the network type. Build-specific native vehicle support must be qualified with the matching simulator and importer binaries recorded in the release receipt. CPU runs anonymously. GPU is explicitly selected and subject to available HF allowance; optional HF sign-in uses the official OAuth flow and needs no personal token entry.
12
 
13
+ The selected track map previews tile layout and asphalt/dirt/ice directly from the selected file. Twenty-eight reconstructed editor-format tracks are included. Settings-only recipes and batches save in the visitor's browser. Formula networks preserve legacy ordered output subsets. Fresh networks for all vehicles require Steering and Acceleration. Rally, Snowmobile and Truck imports must also retain those required outputs; Snowmobile cannot use Handbrake. Formula imports keep the previously supported ordered subsets. Networks have at most 20 inputs (13 raycasts plus 7 other sensors), 12 total layers and 16 neurons per hidden layer. The maximum is `[20]+[16]*10+[5]` (2,869 parameters) for Formula, Rally and Truck; Snowmobile uses up to four outputs (`[20]+[16]*10+[4]`, 2,852 parameters). All 13 game sensor types use original-game defaults for omitted parameters. These limits describe this vanilla worker contract, not unrestricted modified-game networks.
14
 
15
  Application-controlled inputs and intermediate files are temporary. Outputs are held in memory for at most five minutes and deleted sooner after verified download by default; a single-run visitor may explicitly keep the result until that five-minute deadline. This is not a provider-wide zero-data-retention guarantee. Read DATA_POLICY.md and TRACK_LIBRARY.md. Upstream code and license: https://github.com/Zorro909/driving_sim_rs. Open upstream PRs 19 and 21 are not included.
16
 
RELEASE_MANIFEST.json CHANGED
@@ -2,26 +2,29 @@
2
  "backend": "cpu+zerogpu",
3
  "files": {
4
  ".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
5
- "BETA_TESTING.md": "840192b5dec11ab903b05b358d14bd266efd3aaceedcf6d2794f7dc874b9caeb",
6
- "BINARY_PROVENANCE.json": "1116e1757afc6c8629cb2d957e3d77380fe4f7e3186c3832d16a5a08abce6aa8",
7
- "CUDA_REFERENCE.md": "ecee71c9a509702011026ee62bb60ba4e41dac868d6710bcc8c49c8995a2ffeb",
8
- "DATA_POLICY.md": "4d7d0da26a5366ea9c7d33a47dacb8d0d5545174febae170226cc2b924b0a479",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
- "FRONTEND_SOURCE.json": "53a819f3ce95a9393713e8db5e7b112cd0eed15bb57b84a415499436fad6224f",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
14
- "README.md": "164f805743bb6338d469c741d49dab3deac2862ea909481110e8faa358e4f798",
15
  "STORAGE_BOUNDARY.md": "9a1ffb5854230690dba3f0895f9a8e570716de47be2c553de13a6892dd740015",
16
  "TRACK_LIBRARY.md": "66b3656ed84f137d5b6116a0075731cd467818f555cca0969084aff67875319f",
17
  "UPSTREAM.json": "40a2f31fa9abc11e47e247c56909b93b587d1f5be524ab158b24f1f9eed93765",
18
  "app.py": "162486abd6ac7c9281c8e75c15e33373e0fddba2baf6a799dfd54d333fd575d2",
19
  "app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
20
  "assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
 
 
21
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
22
- "bin/altd-sim": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
 
23
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
24
- "bin/libaltd_gpu.so": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
25
  "build_info.py": "93d331c0405cd10076a544f87761bb4a00f6556bbbdab8abc12e070c4661bd78",
26
  "builtin_tracks.py": "2ecc2b1d00fe15701b0271d71e1e68d2e7e59c596330879494055f9b2a99c242",
27
  "builtin_tracks/catalog.json": "65006e70a87a5a53e3738166b0895bc4db9f99767dd891d917b68029abb4e80a",
@@ -53,14 +56,14 @@
53
  "builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
54
  "builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
55
  "builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
56
- "client.js": "93af3e91c0c5fe56ea0d95c40bb26b3e81aff3d36c38b035b4666a4d0955563a",
57
  "delivery.py": "07453999c3831a16e8b1fcc2b4ae5fb28beb7d3952a3fae8de65d16eb6f11e5b",
58
  "gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
59
  "hf-auth.js": "d5cf17b961d1f2efa9d4648d33ba86a148eff0d542c74a121710c4df35c92936",
60
  "hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
61
- "index.html": "713496757a5fa796cf35eb9fba7a4f29b0eb2f8abdd6c8e3a6fdfd8036a3a30f",
62
  "requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
63
- "server.py": "679a5f36997a2c3c2808e71402588789b8fd3e246b4da4ed0a5f6f5621d138c3",
64
  "steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
65
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
66
  "track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0",
@@ -71,7 +74,7 @@
71
  "vendor/hf-oauth/LICENSE": "d6e7b19451c1b3d1d66353bb4b1274138953b3bfd9ae60c56e77b1f548796982",
72
  "vendor/hf-oauth/index.js": "53282844000a171011e547f6472a3846bb4cecb5071adafea079fcac3a2aee7e",
73
  "vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
74
- "worker.py": "2ddf02d3424bba451aa0031dfd9f06d1ec9e210c245ed36dcbe5c79f3732a9ba"
75
  },
76
  "interface": "single-engine-runner-with-map",
77
  "upstream_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
 
2
  "backend": "cpu+zerogpu",
3
  "files": {
4
  ".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
5
+ "BETA_TESTING.md": "27e2492f9fe87cc04f52de2974b685b44041f7de9fa1155926b66c436f0bc613",
6
+ "BINARY_PROVENANCE.json": "825d98f9ae91d88ee08143b11d1af9dd6f889c37f68dbea24163f718759dda3e",
7
+ "CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
8
+ "DATA_POLICY.md": "d5a4066759c823a34ad68a04cf7d9bfa2e39441b24b9466984d06fdb38eb566c",
9
  "FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
10
+ "FRONTEND_SOURCE.json": "165fc6a32b0c132e73679ad7e69a1b30376ea0ac6a789283b22206e98d7212c9",
11
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
12
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
13
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
14
+ "README.md": "b2e1d4a21c1ffd0d652a6e2448284b358f4e42dbfa8a0af6b1842d55c2f7c954",
15
  "STORAGE_BOUNDARY.md": "9a1ffb5854230690dba3f0895f9a8e570716de47be2c553de13a6892dd740015",
16
  "TRACK_LIBRARY.md": "66b3656ed84f137d5b6116a0075731cd467818f555cca0969084aff67875319f",
17
  "UPSTREAM.json": "40a2f31fa9abc11e47e247c56909b93b587d1f5be524ab158b24f1f9eed93765",
18
  "app.py": "162486abd6ac7c9281c8e75c15e33373e0fddba2baf6a799dfd54d333fd575d2",
19
  "app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
20
  "assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
21
+ "assets/rally_template.json": "7350a3fe28d9b4da7a0965ae6ea7ca3472fb7885303e342310d63a0dce80851c",
22
+ "assets/snowmobile_template.json": "12d30545876011fd6fccdd3e721f9c465938c9c58ac99338205481d5e7ac6742",
23
  "assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
24
+ "assets/truck_template.json": "a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7",
25
+ "bin/altd-sim": "0135ecc3d435a9d327be7a92e048cfb5c5291a02ef1e0dddd6ead1cc19b31166",
26
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
27
+ "bin/libaltd_gpu.so": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
28
  "build_info.py": "93d331c0405cd10076a544f87761bb4a00f6556bbbdab8abc12e070c4661bd78",
29
  "builtin_tracks.py": "2ecc2b1d00fe15701b0271d71e1e68d2e7e59c596330879494055f9b2a99c242",
30
  "builtin_tracks/catalog.json": "65006e70a87a5a53e3738166b0895bc4db9f99767dd891d917b68029abb4e80a",
 
56
  "builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
57
  "builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
58
  "builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
59
+ "client.js": "f227469481a6a393f78636fde214473f54219c8af016050b35c6ef1af86eff34",
60
  "delivery.py": "07453999c3831a16e8b1fcc2b4ae5fb28beb7d3952a3fae8de65d16eb6f11e5b",
61
  "gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
62
  "hf-auth.js": "d5cf17b961d1f2efa9d4648d33ba86a148eff0d542c74a121710c4df35c92936",
63
  "hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
64
+ "index.html": "ef759a06305e94edb5ed0e49a587db8c39e3833ec2e02a1bec441c0287c385fd",
65
  "requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
66
+ "server.py": "e00369e6840f0cab5350824e95fc0577ae59524d87ad0a34c32795708be17662",
67
  "steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
68
  "track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
69
  "track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0",
 
74
  "vendor/hf-oauth/LICENSE": "d6e7b19451c1b3d1d66353bb4b1274138953b3bfd9ae60c56e77b1f548796982",
75
  "vendor/hf-oauth/index.js": "53282844000a171011e547f6472a3846bb4cecb5071adafea079fcac3a2aee7e",
76
  "vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
77
+ "worker.py": "481ba85e6edceb0ed6aa993b028029a2f10ab2d7c983ef16c2a4cdcd7c084894"
78
  },
79
  "interface": "single-engine-runner-with-map",
80
  "upstream_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
assets/rally_template.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vehicle": {
3
+ "type": "Rally",
4
+ "mass": 3,
5
+ "inertia_property": 0,
6
+ "inertia_server": 1171.25,
7
+ "shape_size": [
8
+ 62,
9
+ 29
10
+ ],
11
+ "shape_position": [
12
+ 0,
13
+ 0
14
+ ],
15
+ "shape_rotation": 1.5708,
16
+ "gravity_scale": 1,
17
+ "linear_damp": 0,
18
+ "angular_damp": 0,
19
+ "max_contacts_reported": 4,
20
+ "continuous_cd": "Disabled",
21
+ "friction": 0.95,
22
+ "bounce": 0.1,
23
+ "grip": 2.25,
24
+ "steering_speed": 0.4000000059604645,
25
+ "center_steering": true,
26
+ "air_resistance": 0.15,
27
+ "max_velocity": 1000,
28
+ "surfaces": {
29
+ "asphalt": {
30
+ "grip": 1,
31
+ "power": 0.77,
32
+ "steering": 1
33
+ },
34
+ "dirt": {
35
+ "grip": 0.9,
36
+ "power": 0.82,
37
+ "steering": 1
38
+ },
39
+ "ice": {
40
+ "grip": 0.42,
41
+ "power": 0.6,
42
+ "steering": 1
43
+ }
44
+ },
45
+ "wheels": [
46
+ {
47
+ "position": [
48
+ -14,
49
+ -24
50
+ ],
51
+ "steering": true,
52
+ "max_angle_deg": 35,
53
+ "power": 2.5,
54
+ "brake_power": 3.5,
55
+ "handbrake_power": 0
56
+ },
57
+ {
58
+ "position": [
59
+ 14,
60
+ -24
61
+ ],
62
+ "steering": true,
63
+ "max_angle_deg": 35,
64
+ "power": 2.5,
65
+ "brake_power": 3.5,
66
+ "handbrake_power": 0
67
+ },
68
+ {
69
+ "position": [
70
+ -14,
71
+ 24
72
+ ],
73
+ "steering": false,
74
+ "max_angle_deg": 0,
75
+ "power": 3.5,
76
+ "brake_power": 0,
77
+ "handbrake_power": 0
78
+ },
79
+ {
80
+ "position": [
81
+ 14,
82
+ 24
83
+ ],
84
+ "steering": false,
85
+ "max_angle_deg": 0,
86
+ "power": 3.5,
87
+ "brake_power": 0,
88
+ "handbrake_power": 0
89
+ }
90
+ ]
91
+ },
92
+ "physics": {
93
+ "real_precision": "single",
94
+ "contact_recycle_radius": 1,
95
+ "contact_max_separation": 1.5,
96
+ "contact_max_allowed_penetration": 0.3,
97
+ "contact_default_bias": 0.8,
98
+ "solver_iterations": 16
99
+ },
100
+ "track": {
101
+ "name": "Generated track template",
102
+ "tiles": [],
103
+ "path": [],
104
+ "walls": [],
105
+ "physics_shapes": []
106
+ },
107
+ "reset_position": [
108
+ 0,
109
+ 0
110
+ ],
111
+ "reset_rotation": 0
112
+ }
assets/snowmobile_template.json ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vehicle": {
3
+ "type": "Snowmobile",
4
+ "mass": 1.5,
5
+ "inertia_property": 0,
6
+ "inertia_server": 552.625732421875,
7
+ "shape_size": [
8
+ 65,
9
+ 14.0002
10
+ ],
11
+ "shape_position": [
12
+ -0.000114441,
13
+ 0.499986
14
+ ],
15
+ "shape_rotation": 1.5708,
16
+ "gravity_scale": 1,
17
+ "linear_damp": 0,
18
+ "angular_damp": 0,
19
+ "max_contacts_reported": 4,
20
+ "continuous_cd": "Disabled",
21
+ "friction": 0.95,
22
+ "bounce": 0.1,
23
+ "grip": 2,
24
+ "steering_speed": 0.2,
25
+ "center_steering": true,
26
+ "air_resistance": 0.3,
27
+ "max_velocity": 600,
28
+ "surfaces": {
29
+ "asphalt": {
30
+ "grip": 0.9,
31
+ "power": 0.9,
32
+ "steering": 0.25
33
+ },
34
+ "dirt": {
35
+ "grip": 0.7,
36
+ "power": 0.8,
37
+ "steering": 0.7
38
+ },
39
+ "ice": {
40
+ "grip": 0.4,
41
+ "power": 0.8,
42
+ "steering": 0.7
43
+ }
44
+ },
45
+ "wheels": [
46
+ {
47
+ "position": [
48
+ -10,
49
+ -25
50
+ ],
51
+ "steering": true,
52
+ "max_angle_deg": 35,
53
+ "power": 0,
54
+ "brake_power": 0,
55
+ "handbrake_power": 0
56
+ },
57
+ {
58
+ "position": [
59
+ 10,
60
+ -25
61
+ ],
62
+ "steering": true,
63
+ "max_angle_deg": 35,
64
+ "power": 0,
65
+ "brake_power": 0,
66
+ "handbrake_power": 0
67
+ },
68
+ {
69
+ "position": [
70
+ 0,
71
+ 28
72
+ ],
73
+ "steering": false,
74
+ "max_angle_deg": 0,
75
+ "power": 1.3,
76
+ "brake_power": 1.5,
77
+ "handbrake_power": 0
78
+ },
79
+ {
80
+ "position": [
81
+ 0,
82
+ 22
83
+ ],
84
+ "steering": false,
85
+ "max_angle_deg": 0,
86
+ "power": 1.3,
87
+ "brake_power": 1.5,
88
+ "handbrake_power": 0
89
+ },
90
+ {
91
+ "position": [
92
+ 0,
93
+ 16
94
+ ],
95
+ "steering": false,
96
+ "max_angle_deg": 0,
97
+ "power": 1.3,
98
+ "brake_power": 1.5,
99
+ "handbrake_power": 0
100
+ }
101
+ ]
102
+ },
103
+ "physics": {
104
+ "real_precision": "single",
105
+ "contact_recycle_radius": 1,
106
+ "contact_max_separation": 1.5,
107
+ "contact_max_allowed_penetration": 0.3,
108
+ "contact_default_bias": 0.8,
109
+ "solver_iterations": 16
110
+ },
111
+ "track": {
112
+ "name": "Generated track template",
113
+ "tiles": [],
114
+ "path": [],
115
+ "walls": [],
116
+ "physics_shapes": []
117
+ },
118
+ "reset_position": [
119
+ 0,
120
+ 0
121
+ ],
122
+ "reset_rotation": 0
123
+ }
assets/truck_template.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vehicle": {
3
+ "type": "Truck",
4
+ "mass": 8,
5
+ "inertia_property": 0,
6
+ "inertia_server": 11059.5,
7
+ "shape_size": [
8
+ 124.5,
9
+ 33
10
+ ],
11
+ "shape_position": [
12
+ 0,
13
+ 1.25
14
+ ],
15
+ "shape_rotation": 1.5708,
16
+ "gravity_scale": 1,
17
+ "linear_damp": 0,
18
+ "angular_damp": 0,
19
+ "max_contacts_reported": 4,
20
+ "continuous_cd": "Disabled",
21
+ "friction": 0.95,
22
+ "bounce": 0.1,
23
+ "grip": 12,
24
+ "steering_speed": 0.15,
25
+ "center_steering": true,
26
+ "air_resistance": 0.4,
27
+ "max_velocity": 600,
28
+ "surfaces": {
29
+ "asphalt": {
30
+ "grip": 1,
31
+ "power": 0.85,
32
+ "steering": 1
33
+ },
34
+ "dirt": {
35
+ "grip": 0.65,
36
+ "power": 0.8,
37
+ "steering": 1
38
+ },
39
+ "ice": {
40
+ "grip": 0.15,
41
+ "power": 0.7,
42
+ "steering": 1
43
+ }
44
+ },
45
+ "wheels": [
46
+ {
47
+ "position": [
48
+ -17,
49
+ -51
50
+ ],
51
+ "steering": true,
52
+ "max_angle_deg": 22,
53
+ "power": 0,
54
+ "brake_power": 3.5,
55
+ "handbrake_power": 0
56
+ },
57
+ {
58
+ "position": [
59
+ 17,
60
+ -51
61
+ ],
62
+ "steering": true,
63
+ "max_angle_deg": 22,
64
+ "power": 0,
65
+ "brake_power": 3.5,
66
+ "handbrake_power": 0
67
+ },
68
+ {
69
+ "position": [
70
+ -17,
71
+ 46
72
+ ],
73
+ "steering": false,
74
+ "max_angle_deg": 0,
75
+ "power": 6,
76
+ "brake_power": 3,
77
+ "handbrake_power": 3
78
+ },
79
+ {
80
+ "position": [
81
+ 17,
82
+ 46
83
+ ],
84
+ "steering": false,
85
+ "max_angle_deg": 0,
86
+ "power": 6,
87
+ "brake_power": 3,
88
+ "handbrake_power": 3
89
+ }
90
+ ]
91
+ },
92
+ "physics": {
93
+ "real_precision": "single",
94
+ "contact_recycle_radius": 1,
95
+ "contact_max_separation": 1.5,
96
+ "contact_max_allowed_penetration": 0.3,
97
+ "contact_default_bias": 0.8,
98
+ "solver_iterations": 16
99
+ },
100
+ "track": {
101
+ "name": "Generated track template",
102
+ "tiles": [],
103
+ "path": [],
104
+ "walls": [],
105
+ "physics_shapes": []
106
+ },
107
+ "reset_position": [
108
+ 0,
109
+ 0
110
+ ],
111
+ "reset_rotation": 0
112
+ }
bin/altd-sim CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7
3
- size 13911800
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0135ecc3d435a9d327be7a92e048cfb5c5291a02ef1e0dddd6ead1cc19b31166
3
+ size 15774792
bin/libaltd_gpu.so CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a
3
- size 3933424
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca
3
+ size 4711704
client.js CHANGED
@@ -99,7 +99,9 @@ async function checkSteamLeaderboard(trackInfo,report){
99
  const status=$('leaderboard_status'),optIn=$('leaderboard_opt_in');
100
  if(!optIn?.checked)return;
101
  const lap=report?.best_lap_seconds;
 
102
  if(typeof lap!=='number'||!Number.isFinite(lap)||lap<=0){status.textContent='Steam check not run: no completed best lap was reported.';return;}
 
103
  if(trackInfo?.source!=='builtin'||typeof trackInfo.id!=='string'||typeof trackInfo.sha256!=='string'){
104
  status.textContent='Steam check unavailable for custom or unidentified tracks. Your run result is unaffected.';return;
105
  }
@@ -109,7 +111,7 @@ async function checkSteamLeaderboard(trackInfo,report){
109
  status.textContent='Checking the public Steam board in the background…';
110
  const timer=setTimeout(()=>controller.abort(),8000);
111
  try{
112
- const response=await fetch('/api/leaderboard/compare',{method:'POST',cache:'no-store',credentials:'same-origin',signal:controller.signal,headers:{'Content-Type':'application/json'},body:JSON.stringify({track_id:trackInfo.id,track_sha256:trackInfo.sha256,vehicle_type:0,lap_seconds:lap})});
113
  const result=await response.json();
114
  if(generation!==leaderboardGeneration)return;
115
  if(!response.ok)throw Error('Steam check unavailable');
@@ -209,6 +211,7 @@ $('run').onclick = async () => {
209
  $('runSummary').textContent=r?[
210
  'Build: '+(r.build?.build_id??'Not reported'),
211
  'Backend: '+job.backend.toUpperCase(),
 
212
  'Track: '+(trackInfo?.source==='builtin'?trackInfo.display_name:'Custom upload'),
213
  'Generations: '+r.generations_completed+' / '+r.generations_requested+' · Population: '+r.population,
214
  'Server processing: '+metric(r.elapsed_seconds)+' s',
 
99
  const status=$('leaderboard_status'),optIn=$('leaderboard_opt_in');
100
  if(!optIn?.checked)return;
101
  const lap=report?.best_lap_seconds;
102
+ const vehicleType=report?.vehicle_type;
103
  if(typeof lap!=='number'||!Number.isFinite(lap)||lap<=0){status.textContent='Steam check not run: no completed best lap was reported.';return;}
104
+ if(!Number.isInteger(vehicleType)||vehicleType<0||vehicleType>3){status.textContent='Steam check not run: the completed report did not identify a supported vehicle.';return;}
105
  if(trackInfo?.source!=='builtin'||typeof trackInfo.id!=='string'||typeof trackInfo.sha256!=='string'){
106
  status.textContent='Steam check unavailable for custom or unidentified tracks. Your run result is unaffected.';return;
107
  }
 
111
  status.textContent='Checking the public Steam board in the background…';
112
  const timer=setTimeout(()=>controller.abort(),8000);
113
  try{
114
+ const response=await fetch('/api/leaderboard/compare',{method:'POST',cache:'no-store',credentials:'same-origin',signal:controller.signal,headers:{'Content-Type':'application/json'},body:JSON.stringify({track_id:trackInfo.id,track_sha256:trackInfo.sha256,vehicle_type:vehicleType,lap_seconds:lap})});
115
  const result=await response.json();
116
  if(generation!==leaderboardGeneration)return;
117
  if(!response.ok)throw Error('Steam check unavailable');
 
211
  $('runSummary').textContent=r?[
212
  'Build: '+(r.build?.build_id??'Not reported'),
213
  'Backend: '+job.backend.toUpperCase(),
214
+ 'Vehicle: '+(Number.isInteger(r.vehicle_type)&&r.vehicle_type>=0&&r.vehicle_type<=3?['Formula','Rally','Snowmobile','Truck'][r.vehicle_type]+' (Type '+r.vehicle_type+')':'Not reported'),
215
  'Track: '+(trackInfo?.source==='builtin'?trackInfo.display_name:'Custom upload'),
216
  'Generations: '+r.generations_completed+' / '+r.generations_requested+' · Population: '+r.population,
217
  'Server processing: '+metric(r.elapsed_seconds)+' s',
index.html CHANGED
@@ -29,7 +29,7 @@
29
  })();
30
  </script>
31
  <header><div class="eyebrow">AI LEARNS TO DRIVE · TRAINING LAB</div><h1>Train, inspect, repeat.</h1><p class="intro">Pick a track and network, run a bounded training session, and keep your recipes in this browser.</p><details class="about"><summary>About this beta and its data handling</summary><p>Simulator by <a href="https://github.com/Zorro909/driving_sim_rs">Zorro909</a>; interface and hosting by <a href="https://github.com/seeker-cyber-maker/driving_sim_rs">TiGa</a>. Inspired by the <a href="https://store.steampowered.com/app/3312030/AI_Learns_To_Drive/">game by ActivationFunction</a>. Built-in tracks are reconstructed replicas. Star challenges are not evaluated here.</p><p>Uploaded files are used for the requested run. Results are held briefly in application memory and deleted after verified download or expiry. Browser recipes contain settings only. <a href="/policy" target="_blank" rel="noopener">Read the data policy</a>.</p></details><p><a id="feedbackLink" href="https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new" target="_blank" rel="noopener">Report a problem on GitHub</a> · Opens an editable draft and never submits it. Review details before posting; export a run receipt separately if it helps explain the issue.</p><p id="buildLabel" class="hint">Build: connecting…</p></header>
32
- <nav class="tabs" aria-label="Lab sections"><button data-tab="drive" aria-selected="true">1 · Drive & view</button><button data-tab="training" aria-selected="false">2 · Training runs & presets</button><button data-tab="batch" aria-selected="false">3 · Batches</button><button data-tab="editor" aria-selected="false">4 · Network editor</button></nav><div id="drive" class="pane"><div class="grid"><section class="card"><h2>Simulation</h2><button id="run" disabled>Run training</button><p class="hint">Select or create a network below to enable training. Review settings on tab 2 before running.</p><p>Supports the native Formula controls: steering, acceleration, handbrake, brake and boost. Network shape and supported sensors are bounded by the original game contract.</p>
33
  <p id="computeBlock"><label for="backend">Compute</label><select id="backend" disabled><option value="cpu">CPU — no GPU allowance</option><option id="gpuOption" value="gpu" disabled>GPU — uses GPU allowance</option></select></p><p id="backendNote" class="hint">Checking available backends…</p>
34
  <div id="connectionRecovery" hidden><button id="retry" type="button">Reconnect to app</button><p class="hint">Checks server availability. Does not restart training, sign you in, or reset GPU allowance.</p></div>
35
  <div id="gpuAccount" aria-label="Optional GPU account"><p><button id="hfSignIn" type="button" disabled>Sign in with HF for account GPU allowance</button><span id="hfAccount" hidden></span> <button id="hfSignOut" type="button" disabled hidden>Disconnect account</button></p><p id="hfIdentity" role="status" class="hint">CPU needs no sign-in. Checking optional GPU account connection…</p>
@@ -38,7 +38,7 @@
38
  <p data-track-status role="status" class="hint">Loading built-in replica tracks…</p>
39
 
40
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
41
- <p><label>Formula network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
42
  <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. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
43
  </details></section><section class="card"><h2>Selected track &amp; terrain</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></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>
44
  <p><button id="saveLocal" disabled>Save received result again (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
@@ -64,7 +64,7 @@
64
  </details>
65
  <details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
66
  <label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance">First laps · distance only</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>
67
- <div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current Formula runner accepts these metrics; choose them for the behavior you want to train.</small>
68
  </details></div>
69
  <details id="run_settings"><summary>Run settings · timing and elimination</summary><div class="row"><div><label for="control_hz">Decisions per second</label><select id="control_hz" disabled><option>60</option><option>30</option><option>15</option></select></div><div><label for="workers">Parallel simulations</label><select id="workers" disabled><option>1</option><option selected>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></details></div><div id="libraries" class="card"><h3>Recipes · A–J · saved in this browser</h3>
70
  <p>Each recipe contains the training settings and reward mix. Tracks, networks and results stay out of the recipe library. Saving a recipe sends nothing to the server. Settings are sent when you start a run.</p>
@@ -75,7 +75,7 @@
75
  <p>Recipes are specific to this browser and site. Clearing site data removes them. Export a backup to move them between the local runner and HF. Browser privacy settings may prevent saving.</p>
76
  <details><summary>Advanced recipe JSON</summary><textarea id="recipe_draft" rows="12" style="width:100%" aria-label="Recipe settings JSON"></textarea><button id="recipe_apply_draft">Apply JSON to form</button></details></div></section>
77
  <section id="batch" class="pane" hidden><div class="card"><h2>Training batches · A–J</h2><p>Choose files and CPU/GPU on Drive & view, then start a saved batch here. Up to 20 runs and 4,000,000 vehicle-ticks in total. Recipes freeze at start. Each server result is automatically deleted after verified receipt. The last candidate is kept in browser memory. Stop prevents the next run; the current run finishes.</p><label for="batch_slot">Batch slot</label><select id="batch_slot" disabled><option>A</option><option>B</option><option>C</option><option>D</option><option>E</option><option>F</option><option>G</option><option>H</option><option>I</option><option>J</option></select><label for="batch_name">Display name</label><input id="batch_name" type="text" maxlength="80" value="My curriculum" disabled><label><input id="carry" type="checkbox" checked disabled> Continue from the previous run’s candidate</label><p class="hint">Unchecked: each run starts from the original selected network. Repeated run references are allowed. Recipes freeze when the batch starts.</p><label for="batch_recipe_sequence">Recipe sequence (comma-separated slots)</label><input id="batch_recipe_sequence" value="A" maxlength="300"><label for="batch_add_recipe">Add recipe<select id="batch_add_recipe"><option>A</option><option>B</option><option>C</option><option>D</option><option>E</option><option>F</option><option>G</option><option>H</option><option>I</option><option>J</option></select></label><button id="queue_add" disabled>+ Add run</button><div class="toolbar"><button id="batch_save" disabled>Save batch</button><button id="batch_load" disabled>Load batch</button><button class="primary" id="batch_start" disabled>Start saved batch</button><button id="batch_stop" disabled>Stop after current run</button><button id="batch_export" disabled>Export batch receipt</button></div><div id="batch_status" role="status">No batch selected.</div><div id="batch_history"></div><div id="batches_feedback" role="status" aria-live="polite"></div></div></section>
78
- <section id="editor" class="pane" hidden><div class="card"><h2>Network editor</h2><p class="hint">An original editor inspired by <a href="https://the-mars-guy.github.io/AI-Learns-To-Drive-Tool/" target="_blank" rel="noopener">Mars’s network creator</a>. Create networks for any ordered subset of the five native controls, or use the largest original-game shape. Loaded networks keep their original output order and sensor parameters. Unsupported files can still be inspected without changing the original.</p><div class="toolbar"><label for="editor_file">Load an existing .evolution file</label><input id="editor_file" type="file" accept=".evolution"><button id="editor_import" disabled>Inspect selected network</button><button id="editor_create" disabled>Create fresh network</button><button id="editor_apply" disabled>Use edited network</button><a id="editor_download" hidden download>Download .evolution</a></div><div class="row"><div><label for="editor_name">Network name</label><input id="editor_name" type="text" maxlength="80" value="Fresh network" disabled><label for="editor_preset">Fresh network preset</label><select id="editor_preset" disabled><option value="small">Small starter · 6 inputs, 4 hidden nodes, 5 outputs</option><option value="maximum">Largest game network · 20 inputs, 10 × 16 hidden nodes, 5 outputs</option><option value="custom">Custom</option></select><label for="editor_shape">Input and hidden layer sizes</label><input id="editor_shape" type="text" value="6,4" disabled><small>Enter 1–20 inputs, followed by 0–10 hidden layers of 1–16 nodes. Output width follows the selected controls. Maximum shape: 20 → ten layers of 16 → 5 (2,869 parameters).</small><fieldset id="editor_outputs" disabled><legend>Fresh network outputs</legend><div class="output-options"><label><input id="editor_output_0" type="checkbox" value="0" checked disabled> Steering (0)</label><label><input id="editor_output_1" type="checkbox" value="1" checked disabled> Acceleration (1)</label><label><input id="editor_output_2" type="checkbox" value="2" checked disabled> Handbrake (2)</label><label><input id="editor_output_3" type="checkbox" value="3" checked disabled> Brake (3)</label><label><input id="editor_output_4" type="checkbox" value="4" checked disabled> Boost (4)</label></div><small>Choose at least one. Fresh output IDs follow this order. Loaded network output order is preserved when editing or exporting.</small></fieldset></div><div><label for="editor_seed">Initialization seed</label><input id="editor_seed" type="number" min="0" max="2147483647" value="42105" disabled><label><input id="editor_xavier" type="checkbox" checked disabled> Seeded Xavier uniform weights (browser algorithm)</label><label><input id="editor_bias" type="checkbox" disabled> Xavier uniform biases</label><small>Unchecked: zeros. Biases default to zero.</small></div></div><p id="editor_status" role="status">Choose a file or create a fresh network. Editor changes are browser-local until you explicitly start a run.</p><p id="editor_metadata" class="hint"></p><p id="editor_legality" class="hint"></p><details id="editor_history_panel"><summary>Training history · recorded generations</summary><div class="table-scroll"><table><thead><tr><th>Record</th><th>Time</th><th>Mutation</th><th>Best score</th><th>Best lap</th></tr></thead><tbody id="editor_history"></tbody></table></div><details><summary>Full saved training metadata</summary><pre id="editor_stats"></pre></details></details><canvas aria-label="Network architecture preview" id="network_map" width="1100" height="450"></canvas><details id="weight_values"><summary>Individual weight and bias values</summary><div class="table-scroll" style="max-height:420px;overflow:auto"><table><thead><tr><th>Connection / bias</th><th>Value</th></tr></thead><tbody id="editor_parameters"></tbody></table></div></details><details><summary>Weights, biases and input contract</summary><pre id="editor_contract"></pre><label for="editor_json">NeuralNetwork JSON · editable weights and biases</label><textarea id="editor_json" rows="16" style="width:100%;box-sizing:border-box;background:#0c1725;color:#e5edf5" disabled></textarea></details></div></section><script>/* Settings-only recipe contract. Storage is injected; no network or job data. */
79
  (function(root){
80
  const KEY='tiga.ald.recipes.v1';
81
  const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
@@ -168,6 +168,7 @@
168
  </script><script>/* Pure browser/Node structural checks and deterministic fresh initialization. */
169
  (function(root){
170
  const scalarTypes=['speed','velocityFront','velocitySide','angularVelocity','wheelAngle','boostCapacity','correctDirection'];
 
171
  const outputsValid=outputs=>Array.isArray(outputs)&&outputs.length>=1&&outputs.length<=5&&outputs.every(x=>Number.isInteger(x)&&x>=0&&x<=4)&&new Set(outputs).size===outputs.length;
172
  function neural(value){
173
  if(!value||!Array.isArray(value.Shape)||value.Shape.length<2||value.Shape.length>12||value.Shape.some(n=>!Number.isInteger(n)||n<1||n>20))throw Error('Shape must contain 2–12 layers with 1–20 inputs');
@@ -188,7 +189,10 @@
188
  }
189
  function compatible(value){
190
  const n=neural(value?.NeuralNetwork),s=value.Sensors;
191
- if(value.Type!==0||!outputsValid(value.Outputs)||n.Shape.at(-1)!==value.Outputs.length)throw Error('Formula outputs must be a unique ordered subset of IDs 0–4 matching the output width');
 
 
 
192
  if(n.Shape[0]>20||n.Shape.slice(1,-1).some(x=>x>16)||n.Shape.length>12)throw Error('Shape exceeds the original-game limits');
193
  if(!Array.isArray(s)||s.length!==n.Shape[0])throw Error('Sensor count does not match input shape');
194
  let rays=0,other=0;
@@ -229,9 +233,13 @@
229
  if(!id)throw Error('Secure GUID generation is unavailable');
230
  return {Id:id,Name:name.trim(),Type:source.Type,Stats:{Generations:[]},Snapshots:[],Outputs:[...source.Outputs],Sensors:JSON.parse(JSON.stringify(source.Sensors)),NeuralNetwork:network};
231
  }
232
- function fresh({shape,outputs=[0,1,2,3,4],seed,xavier=true,bias=false,name='Fresh network'}){
 
 
233
  if(!Array.isArray(shape)||shape.length<1||shape.length>11||shape.some(n=>!Number.isInteger(n)||n<1)||shape[0]>20||shape.slice(1).some(n=>n>16))throw Error('Fresh shape: 1–20 inputs and 0–10 hidden layers of 1–16 nodes');
234
  if(!outputsValid(outputs))throw Error('Choose one to five unique output IDs from 0–4');
 
 
235
  const fullShape=[...shape,outputs.length];if(fullShape.length>12)throw Error('Fresh networks allow at most 12 layers');
236
  if(!Number.isInteger(seed)||seed<0||seed>2147483647)throw Error('Seed must be 0–2147483647');
237
  if(typeof xavier!=='boolean'||typeof bias!=='boolean')throw Error('Invalid initialization switches');
@@ -246,9 +254,9 @@
246
  const rays=Math.min(13,shape[0]-1),extra=shape[0]-1-rays;
247
  const sensors=[{$type:'speed'},...scalarTypes.slice(1,1+extra).map($type=>({$type}))];
248
  for(let i=0;i<rays;i++)sensors.push({$type:'raycast',Degrees:rays===1?0:-90+180*i/(rays-1),Length:800});
249
- return edited({Type:0,Outputs:[...outputs],Sensors:sensors},n,name);
250
  }
251
- const api={neural,compatible,edited,fresh,outputsValid};
252
  if(typeof module!=='undefined'&&module.exports)module.exports=api;else root.NetworkEditor=api;
253
  })(typeof window!=='undefined'?window:globalThis);
254
  </script><script>(() => {
@@ -452,13 +460,26 @@ document.querySelectorAll('[data-tab]').forEach(button=>button.addEventListener(
452
  const q=id=>document.getElementById(id),api=window.NetworkEditor;
453
  const status=text=>q('editor_status').textContent=text;
454
  let source=null,exportURL=null;
455
- for(const id of ['editor_name','editor_preset','editor_shape','editor_seed','editor_xavier','editor_bias','editor_create','editor_import','editor_outputs',...Array.from({length:5},(_,i)=>'editor_output_'+i)])q(id).disabled=false;
456
  const outputIds=[0,1,2,3,4],outputName=id=>'editor_output_'+id;
457
  function setOutputs(ids){for(const id of outputIds)q(outputName(id)).checked=ids.includes(id);}
458
- function preset(value){if(value==='small'){q('editor_shape').value='6,4';setOutputs(outputIds);}else if(value==='maximum'){q('editor_shape').value=[20,...Array(10).fill(16)].join(',');setOutputs(outputIds);}}
 
 
 
 
 
 
 
 
 
 
 
459
  q('editor_preset').onchange=()=>preset(q('editor_preset').value);
 
460
  q('editor_shape').oninput=()=>q('editor_preset').value='custom';
461
- for(const id of outputIds)q(outputName(id)).onchange=()=>q('editor_preset').value='custom';
 
462
  window.setEditorBusy=busy=>{q('editor_apply').disabled=busy||!source;};
463
  function graph(n){
464
  const canvas=q('network_map'),ctx=canvas.getContext('2d');ctx.clearRect(0,0,canvas.width,canvas.height);
@@ -471,10 +492,11 @@ document.querySelectorAll('[data-tab]').forEach(button=>button.addEventListener(
471
  }
472
  function show(value){
473
  const n=api.neural(value.NeuralNetwork);source=value;
 
474
  const count=n.Weights.reduce((sum,m)=>sum+m.reduce((s,r)=>s+r.length,0),0)+n.Biases.reduce((s,r)=>s+r.length,0);
475
  q('editor_json').value=JSON.stringify(n,null,2);q('editor_json').disabled=false;
476
- q('editor_name').value=value.Name||'Edited network';q('editor_shape').value=n.Shape.slice(0,-1).join(',');q('editor_preset').value='custom';setOutputs(Array.isArray(value.Outputs)?value.Outputs:[]);
477
- q('editor_metadata').textContent=n.Shape.join(' → ')+' · '+count+' parameters. Structure checked; no game/leaderboard validation claimed.';
478
  q('editor_contract').textContent=JSON.stringify({sensors:value.Sensors,outputs:value.Outputs,vehicle:value.Type},null,2);
479
  try{api.compatible(value);q('editor_legality').textContent='Supported by the current training worker.';}
480
  catch(error){q('editor_legality').textContent='Inspection/export only: '+error.message;}
@@ -520,13 +542,13 @@ document.querySelectorAll('[data-tab]').forEach(button=>button.addEventListener(
520
  if(!source)throw Error('Load or create a network first');
521
  const next=JSON.parse(q('editor_json').value);
522
  for(const input of q('editor_parameters').querySelectorAll('input'))if(input.value!==input.dataset.initial)updateParameter(next,input);
523
- const value=api.edited(source,next,q('editor_name').value);
524
  const blob=await new Response(new Blob([JSON.stringify(value)]).stream().pipeThrough(new CompressionStream('gzip'))).blob();
525
  if(blob.size>1048576)throw Error('Export exceeds 1 MB');
526
  return {value,file:new File([blob],'edited-network.evolution',{type:'application/octet-stream'})};
527
  }
528
  q('editor_file').onchange=load;q('editor_import').onclick=load;
529
- q('editor_create').onclick=()=>{try{const outputs=outputIds.filter(id=>q(outputName(id)).checked);show(api.fresh({shape:q('editor_shape').value.split(',').map(Number),outputs,seed:Number(q('editor_seed').value),xavier:q('editor_xavier').checked,bias:q('editor_bias').checked,name:q('editor_name').value}));status('Fresh browser-seeded network created. No training history, upload or storage.');}catch(error){status('Not created: '+error.message);}};
530
  q('editor_apply').onclick=async()=>{try{const {value,file}=await artifact();api.compatible(value);window.TrainingClient.useNetwork(file);show(value);status('Edited network selected for the next run. No upload yet.');}catch(error){status('Not applied: '+error.message);}};
531
  q('editor_download').onclick=async event=>{
532
  event.preventDefault();try{const {file}=await artifact();if(exportURL)URL.revokeObjectURL(exportURL);exportURL=URL.createObjectURL(file);const a=document.createElement('a');a.href=exportURL;a.download=file.name;a.click();status('Export requested. This is a new edited artifact with no inherited training scores.');}catch(error){status('Not exported: '+error.message);}
 
29
  })();
30
  </script>
31
  <header><div class="eyebrow">AI LEARNS TO DRIVE · TRAINING LAB</div><h1>Train, inspect, repeat.</h1><p class="intro">Pick a track and network, run a bounded training session, and keep your recipes in this browser.</p><details class="about"><summary>About this beta and its data handling</summary><p>Simulator by <a href="https://github.com/Zorro909/driving_sim_rs">Zorro909</a>; interface and hosting by <a href="https://github.com/seeker-cyber-maker/driving_sim_rs">TiGa</a>. Inspired by the <a href="https://store.steampowered.com/app/3312030/AI_Learns_To_Drive/">game by ActivationFunction</a>. Built-in tracks are reconstructed replicas. Star challenges are not evaluated here.</p><p>Uploaded files are used for the requested run. Results are held briefly in application memory and deleted after verified download or expiry. Browser recipes contain settings only. <a href="/policy" target="_blank" rel="noopener">Read the data policy</a>.</p></details><p><a id="feedbackLink" href="https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new" target="_blank" rel="noopener">Report a problem on GitHub</a> · Opens an editable draft and never submits it. Review details before posting; export a run receipt separately if it helps explain the issue.</p><p id="buildLabel" class="hint">Build: connecting…</p></header>
32
+ <nav class="tabs" aria-label="Lab sections"><button data-tab="drive" aria-selected="true">1 · Drive & view</button><button data-tab="training" aria-selected="false">2 · Training runs & presets</button><button data-tab="batch" aria-selected="false">3 · Batches</button><button data-tab="editor" aria-selected="false">4 · Network editor</button></nav><div id="drive" class="pane"><div class="grid"><section class="card"><h2>Simulation</h2><button id="run" disabled>Run training</button><p class="hint">Select or create a network below to enable training. Review settings on tab 2 before running.</p><p>Supports Formula, Rally, Snowmobile and Truck networks. Control outputs follow the original vehicle editor rules. Network shape and supported sensors are bounded by the original game contract.</p>
33
  <p id="computeBlock"><label for="backend">Compute</label><select id="backend" disabled><option value="cpu">CPU — no GPU allowance</option><option id="gpuOption" value="gpu" disabled>GPU — uses GPU allowance</option></select></p><p id="backendNote" class="hint">Checking available backends…</p>
34
  <div id="connectionRecovery" hidden><button id="retry" type="button">Reconnect to app</button><p class="hint">Checks server availability. Does not restart training, sign you in, or reset GPU allowance.</p></div>
35
  <div id="gpuAccount" aria-label="Optional GPU account"><p><button id="hfSignIn" type="button" disabled>Sign in with HF for account GPU allowance</button><span id="hfAccount" hidden></span> <button id="hfSignOut" type="button" disabled hidden>Disconnect account</button></p><p id="hfIdentity" role="status" class="hint">CPU needs no sign-in. Checking optional GPU account connection…</p>
 
38
  <p data-track-status role="status" class="hint">Loading built-in replica tracks…</p>
39
 
40
  <p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
41
+ <p><label>Vehicle network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
42
  <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. All results expire after five minutes. <a href="/policy" target="_blank" rel="noopener">Data policy</a></p>
43
  </details></section><section class="card"><h2>Selected track &amp; terrain</h2><p id="mapStatus" class="map-status" role="status">Loading selected track…</p><div class="map"><canvas id="trackMap" width="1000" height="500" role="img" aria-label="Selected track tile layout and terrain"></canvas></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>
44
  <p><button id="saveLocal" disabled>Save received result again (browser only)</button> <button id="forgetLocal" disabled>Discard browser result</button></p>
 
64
  </details>
65
  <details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
66
  <label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance">First laps · distance only</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>
67
+ <div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current vehicle runner accepts these metrics; choose them for the behavior you want to train.</small>
68
  </details></div>
69
  <details id="run_settings"><summary>Run settings · timing and elimination</summary><div class="row"><div><label for="control_hz">Decisions per second</label><select id="control_hz" disabled><option>60</option><option>30</option><option>15</option></select></div><div><label for="workers">Parallel simulations</label><select id="workers" disabled><option>1</option><option selected>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></details></div><div id="libraries" class="card"><h3>Recipes · A–J · saved in this browser</h3>
70
  <p>Each recipe contains the training settings and reward mix. Tracks, networks and results stay out of the recipe library. Saving a recipe sends nothing to the server. Settings are sent when you start a run.</p>
 
75
  <p>Recipes are specific to this browser and site. Clearing site data removes them. Export a backup to move them between the local runner and HF. Browser privacy settings may prevent saving.</p>
76
  <details><summary>Advanced recipe JSON</summary><textarea id="recipe_draft" rows="12" style="width:100%" aria-label="Recipe settings JSON"></textarea><button id="recipe_apply_draft">Apply JSON to form</button></details></div></section>
77
  <section id="batch" class="pane" hidden><div class="card"><h2>Training batches · A–J</h2><p>Choose files and CPU/GPU on Drive & view, then start a saved batch here. Up to 20 runs and 4,000,000 vehicle-ticks in total. Recipes freeze at start. Each server result is automatically deleted after verified receipt. The last candidate is kept in browser memory. Stop prevents the next run; the current run finishes.</p><label for="batch_slot">Batch slot</label><select id="batch_slot" disabled><option>A</option><option>B</option><option>C</option><option>D</option><option>E</option><option>F</option><option>G</option><option>H</option><option>I</option><option>J</option></select><label for="batch_name">Display name</label><input id="batch_name" type="text" maxlength="80" value="My curriculum" disabled><label><input id="carry" type="checkbox" checked disabled> Continue from the previous run’s candidate</label><p class="hint">Unchecked: each run starts from the original selected network. Repeated run references are allowed. Recipes freeze when the batch starts.</p><label for="batch_recipe_sequence">Recipe sequence (comma-separated slots)</label><input id="batch_recipe_sequence" value="A" maxlength="300"><label for="batch_add_recipe">Add recipe<select id="batch_add_recipe"><option>A</option><option>B</option><option>C</option><option>D</option><option>E</option><option>F</option><option>G</option><option>H</option><option>I</option><option>J</option></select></label><button id="queue_add" disabled>+ Add run</button><div class="toolbar"><button id="batch_save" disabled>Save batch</button><button id="batch_load" disabled>Load batch</button><button class="primary" id="batch_start" disabled>Start saved batch</button><button id="batch_stop" disabled>Stop after current run</button><button id="batch_export" disabled>Export batch receipt</button></div><div id="batch_status" role="status">No batch selected.</div><div id="batch_history"></div><div id="batches_feedback" role="status" aria-live="polite"></div></div></section>
78
+ <section id="editor" class="pane" hidden><div class="card"><h2>Network editor</h2><p class="hint">An original editor inspired by <a href="https://the-mars-guy.github.io/AI-Learns-To-Drive-Tool/" target="_blank" rel="noopener">Mars’s network creator</a>. Create fresh networks with the selected vehicle’s game-legal controls, or use its largest original-game shape. Loaded networks keep their original vehicle, output order and sensor parameters. Unsupported files can still be inspected without changing the original.</p><div class="toolbar"><label for="editor_file">Load an existing .evolution file</label><input id="editor_file" type="file" accept=".evolution"><button id="editor_import" disabled>Inspect selected network</button><button id="editor_create" disabled>Create fresh network</button><button id="editor_apply" disabled>Use edited network</button><a id="editor_download" hidden download>Download .evolution</a></div><div class="row"><div><label for="editor_name">Network name</label><input id="editor_name" type="text" maxlength="80" value="Fresh network" disabled><label for="editor_vehicle">Vehicle type for fresh networks</label><select id="editor_vehicle" disabled><option value="0">Formula</option><option value="1">Rally</option><option value="2">Snowmobile</option><option value="3">Truck</option></select><small>This selector applies only when you create a fresh network. Imported vehicle type is retained and shown with the current network.</small><label for="editor_preset">Fresh network preset</label><select id="editor_preset" disabled><option id="editor_small_label" value="small">Small starter · 6 inputs, 4 hidden nodes, 5 outputs</option><option id="editor_maximum_label" value="maximum">Largest game network · 20 inputs, 10 × 16 hidden nodes, 5 outputs</option><option value="custom">Custom</option></select><label for="editor_shape">Input and hidden layer sizes</label><input id="editor_shape" type="text" value="6,4" disabled><small id="editor_shape_hint">Enter 1–20 inputs, followed by 0–10 hidden layers of 1–16 nodes. Output width follows the selected controls. Maximum shape: 20 → ten layers of 16 → 5 (2,869 parameters).</small><fieldset id="editor_outputs" disabled><legend id="editor_output_legend">Fresh network outputs</legend><div class="output-options"><label><input id="editor_output_0" type="checkbox" value="0" checked disabled> Steering (0)</label><label><input id="editor_output_1" type="checkbox" value="1" checked disabled> Acceleration (1)</label><label><input id="editor_output_2" type="checkbox" value="2" checked disabled> Handbrake (2)</label><label><input id="editor_output_3" type="checkbox" value="3" checked disabled> Brake (3)</label><label><input id="editor_output_4" type="checkbox" value="4" checked disabled> Boost (4)</label></div><small id="editor_output_hint">Steering and Acceleration are required. Fresh output IDs preserve this order.</small></fieldset></div><div><label for="editor_seed">Initialization seed</label><input id="editor_seed" type="number" min="0" max="2147483647" value="42105" disabled><label><input id="editor_xavier" type="checkbox" checked disabled> Seeded Xavier uniform weights (browser algorithm)</label><label><input id="editor_bias" type="checkbox" disabled> Xavier uniform biases</label><small>Unchecked: zeros. Biases default to zero.</small></div></div><p id="editor_status" role="status">Choose a file or create a fresh network. Editor changes are browser-local until you explicitly start a run.</p><p id="editor_metadata" class="hint"></p><p id="editor_legality" class="hint"></p><details id="editor_history_panel"><summary>Training history · recorded generations</summary><div class="table-scroll"><table><thead><tr><th>Record</th><th>Time</th><th>Mutation</th><th>Best score</th><th>Best lap</th></tr></thead><tbody id="editor_history"></tbody></table></div><details><summary>Full saved training metadata</summary><pre id="editor_stats"></pre></details></details><canvas aria-label="Network architecture preview" id="network_map" width="1100" height="450"></canvas><details id="weight_values"><summary>Individual weight and bias values</summary><div class="table-scroll" style="max-height:420px;overflow:auto"><table><thead><tr><th>Connection / bias</th><th>Value</th></tr></thead><tbody id="editor_parameters"></tbody></table></div></details><details><summary>Weights, biases and input contract</summary><pre id="editor_contract"></pre><label for="editor_json">NeuralNetwork JSON · editable weights and biases</label><textarea id="editor_json" rows="16" style="width:100%;box-sizing:border-box;background:#0c1725;color:#e5edf5" disabled></textarea></details></div></section><script>/* Settings-only recipe contract. Storage is injected; no network or job data. */
79
  (function(root){
80
  const KEY='tiga.ald.recipes.v1';
81
  const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
 
168
  </script><script>/* Pure browser/Node structural checks and deterministic fresh initialization. */
169
  (function(root){
170
  const scalarTypes=['speed','velocityFront','velocitySide','angularVelocity','wheelAngle','boostCapacity','correctDirection'];
171
+ const vehicleNames=['Formula','Rally','Snowmobile','Truck'];
172
  const outputsValid=outputs=>Array.isArray(outputs)&&outputs.length>=1&&outputs.length<=5&&outputs.every(x=>Number.isInteger(x)&&x>=0&&x<=4)&&new Set(outputs).size===outputs.length;
173
  function neural(value){
174
  if(!value||!Array.isArray(value.Shape)||value.Shape.length<2||value.Shape.length>12||value.Shape.some(n=>!Number.isInteger(n)||n<1||n>20))throw Error('Shape must contain 2–12 layers with 1–20 inputs');
 
189
  }
190
  function compatible(value){
191
  const n=neural(value?.NeuralNetwork),s=value.Sensors;
192
+ if(!Number.isInteger(value.Type)||value.Type<0||value.Type>=vehicleNames.length)throw Error('Vehicle Type must be Formula (0), Rally (1), Snowmobile (2), or Truck (3)');
193
+ if(!outputsValid(value.Outputs)||n.Shape.at(-1)!==value.Outputs.length)throw Error('Outputs must be a unique ordered subset of IDs 0–4 matching the output width');
194
+ if(value.Type!==0&&(!value.Outputs.includes(0)||!value.Outputs.includes(1)))throw Error(vehicleNames[value.Type]+' networks require Steering and Acceleration outputs');
195
+ if(value.Type===2&&value.Outputs.includes(2))throw Error('Snowmobile Handbrake output is unavailable in the original game editor; the imported network is inspect-only');
196
  if(n.Shape[0]>20||n.Shape.slice(1,-1).some(x=>x>16)||n.Shape.length>12)throw Error('Shape exceeds the original-game limits');
197
  if(!Array.isArray(s)||s.length!==n.Shape[0])throw Error('Sensor count does not match input shape');
198
  let rays=0,other=0;
 
233
  if(!id)throw Error('Secure GUID generation is unavailable');
234
  return {Id:id,Name:name.trim(),Type:source.Type,Stats:{Generations:[]},Snapshots:[],Outputs:[...source.Outputs],Sensors:JSON.parse(JSON.stringify(source.Sensors)),NeuralNetwork:network};
235
  }
236
+ function fresh({type=0,shape,outputs,seed,xavier=true,bias=false,name='Fresh network'}){
237
+ if(!Number.isInteger(type)||type<0||type>=vehicleNames.length)throw Error('Choose Formula, Rally, Snowmobile, or Truck');
238
+ if(outputs===undefined)outputs=type===2?[0,1,3,4]:[0,1,2,3,4];
239
  if(!Array.isArray(shape)||shape.length<1||shape.length>11||shape.some(n=>!Number.isInteger(n)||n<1)||shape[0]>20||shape.slice(1).some(n=>n>16))throw Error('Fresh shape: 1–20 inputs and 0–10 hidden layers of 1–16 nodes');
240
  if(!outputsValid(outputs))throw Error('Choose one to five unique output IDs from 0–4');
241
+ if(!outputs.includes(0)||!outputs.includes(1))throw Error(vehicleNames[type]+' fresh networks require Steering and Acceleration outputs');
242
+ if(type===2&&outputs.includes(2))throw Error('Snowmobile Handbrake output is unavailable in the original game editor');
243
  const fullShape=[...shape,outputs.length];if(fullShape.length>12)throw Error('Fresh networks allow at most 12 layers');
244
  if(!Number.isInteger(seed)||seed<0||seed>2147483647)throw Error('Seed must be 0–2147483647');
245
  if(typeof xavier!=='boolean'||typeof bias!=='boolean')throw Error('Invalid initialization switches');
 
254
  const rays=Math.min(13,shape[0]-1),extra=shape[0]-1-rays;
255
  const sensors=[{$type:'speed'},...scalarTypes.slice(1,1+extra).map($type=>({$type}))];
256
  for(let i=0;i<rays;i++)sensors.push({$type:'raycast',Degrees:rays===1?0:-90+180*i/(rays-1),Length:800});
257
+ return edited({Type:type,Outputs:[...outputs],Sensors:sensors},n,name);
258
  }
259
+ const api={neural,compatible,edited,fresh,outputsValid,vehicleNames};
260
  if(typeof module!=='undefined'&&module.exports)module.exports=api;else root.NetworkEditor=api;
261
  })(typeof window!=='undefined'?window:globalThis);
262
  </script><script>(() => {
 
460
  const q=id=>document.getElementById(id),api=window.NetworkEditor;
461
  const status=text=>q('editor_status').textContent=text;
462
  let source=null,exportURL=null;
463
+ for(const id of ['editor_name','editor_vehicle','editor_preset','editor_shape','editor_seed','editor_xavier','editor_bias','editor_create','editor_import','editor_outputs',...Array.from({length:5},(_,i)=>'editor_output_'+i)])q(id).disabled=false;
464
  const outputIds=[0,1,2,3,4],outputName=id=>'editor_output_'+id;
465
  function setOutputs(ids){for(const id of outputIds)q(outputName(id)).checked=ids.includes(id);}
466
+ const freshType=()=>Number(q('editor_vehicle').value),allowedOutputs=type=>type===2?[0,1,3,4]:outputIds,defaultOutputs=type=>allowedOutputs(type);
467
+ function refreshOutputRules(reset=false){
468
+ const type=freshType(),allowed=allowedOutputs(type);
469
+ if(reset)setOutputs(defaultOutputs(type));
470
+ for(const id of outputIds){const input=q(outputName(id)),required=id===0||id===1,unavailable=!allowed.includes(id);input.disabled=required||unavailable;if(required)input.checked=true;if(unavailable)input.checked=false;}
471
+ q('editor_small_label').textContent='Small starter · 6 inputs, 4 hidden nodes, '+allowed.length+' outputs';
472
+ q('editor_shape_hint').textContent='Enter 1–20 inputs, followed by 0–10 hidden layers of 1–16 nodes. Output width follows the selected controls. Maximum shape: 20 → ten layers of 16 → '+allowed.length+' ('+(2784+17*allowed.length).toLocaleString()+' parameters).';
473
+ q('editor_maximum_label').textContent='Largest game network · 20 inputs, 10 × 16 hidden nodes, '+allowed.length+' outputs ('+(2784+17*allowed.length).toLocaleString()+' parameters)';
474
+ q('editor_output_legend').textContent='Fresh network outputs · '+api.vehicleNames[type];
475
+ q('editor_output_hint').textContent=type===2?'Steering and Acceleration are required. Snowmobile Handbrake is unavailable; at most four outputs.':'Steering and Acceleration are required. Fresh output IDs preserve this order; up to five outputs.';
476
+ }
477
+ function preset(value){if(value==='small'){q('editor_shape').value='6,4';refreshOutputRules(true);}else if(value==='maximum'){q('editor_shape').value=[20,...Array(10).fill(16)].join(',');refreshOutputRules(true);}}
478
  q('editor_preset').onchange=()=>preset(q('editor_preset').value);
479
+ q('editor_vehicle').onchange=()=>refreshOutputRules(q('editor_preset').value!=='custom');
480
  q('editor_shape').oninput=()=>q('editor_preset').value='custom';
481
+ for(const id of outputIds)q(outputName(id)).onchange=()=>{q('editor_preset').value='custom';refreshOutputRules(false);};
482
+ refreshOutputRules(false);
483
  window.setEditorBusy=busy=>{q('editor_apply').disabled=busy||!source;};
484
  function graph(n){
485
  const canvas=q('network_map'),ctx=canvas.getContext('2d');ctx.clearRect(0,0,canvas.width,canvas.height);
 
492
  }
493
  function show(value){
494
  const n=api.neural(value.NeuralNetwork);source=value;
495
+ if(Number.isInteger(value.Type)&&value.Type>=0&&value.Type<api.vehicleNames.length){q('editor_vehicle').value=String(value.Type);refreshOutputRules(false);}
496
  const count=n.Weights.reduce((sum,m)=>sum+m.reduce((s,r)=>s+r.length,0),0)+n.Biases.reduce((s,r)=>s+r.length,0);
497
  q('editor_json').value=JSON.stringify(n,null,2);q('editor_json').disabled=false;
498
+ q('editor_name').value=value.Name||'Edited network';q('editor_shape').value=n.Shape.slice(0,-1).join(',');q('editor_preset').value='custom';setOutputs((Array.isArray(value.Outputs)?value.Outputs:[]).filter(id=>allowedOutputs(freshType()).includes(id)));refreshOutputRules(false);
499
+ q('editor_metadata').textContent='Current network: '+(api.vehicleNames[value.Type]||'Unknown vehicle')+' (Type '+String(value.Type)+') · '+n.Shape.join(' → ')+' · '+count+' parameters. Structure checked; no game/leaderboard validation claimed.';
500
  q('editor_contract').textContent=JSON.stringify({sensors:value.Sensors,outputs:value.Outputs,vehicle:value.Type},null,2);
501
  try{api.compatible(value);q('editor_legality').textContent='Supported by the current training worker.';}
502
  catch(error){q('editor_legality').textContent='Inspection/export only: '+error.message;}
 
542
  if(!source)throw Error('Load or create a network first');
543
  const next=JSON.parse(q('editor_json').value);
544
  for(const input of q('editor_parameters').querySelectorAll('input'))if(input.value!==input.dataset.initial)updateParameter(next,input);
545
+ const value=api.edited(source,next,q('editor_name').value);api.compatible(value);
546
  const blob=await new Response(new Blob([JSON.stringify(value)]).stream().pipeThrough(new CompressionStream('gzip'))).blob();
547
  if(blob.size>1048576)throw Error('Export exceeds 1 MB');
548
  return {value,file:new File([blob],'edited-network.evolution',{type:'application/octet-stream'})};
549
  }
550
  q('editor_file').onchange=load;q('editor_import').onclick=load;
551
+ q('editor_create').onclick=()=>{try{const outputs=outputIds.filter(id=>q(outputName(id)).checked);show(api.fresh({type:freshType(),shape:q('editor_shape').value.split(',').map(Number),outputs,seed:Number(q('editor_seed').value),xavier:q('editor_xavier').checked,bias:q('editor_bias').checked,name:q('editor_name').value}));status('Fresh '+api.vehicleNames[freshType()]+' network created. No training history, upload or storage.');}catch(error){status('Not created: '+error.message);}};
552
  q('editor_apply').onclick=async()=>{try{const {value,file}=await artifact();api.compatible(value);window.TrainingClient.useNetwork(file);show(value);status('Edited network selected for the next run. No upload yet.');}catch(error){status('Not applied: '+error.message);}};
553
  q('editor_download').onclick=async event=>{
554
  event.preventDefault();try{const {file}=await artifact();if(exportURL)URL.revokeObjectURL(exportURL);exportURL=URL.createObjectURL(file);const a=document.createElement('a');a.href=exportURL;a.download=file.name;a.click();status('Export requested. This is a new edited artifact with no inherited training scores.');}catch(error){status('Not exported: '+error.message);}
server.py CHANGED
@@ -35,12 +35,10 @@ def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None
35
  if not isinstance(body,dict) or set(body)!={'track_id','track_sha256','vehicle_type','lap_seconds'}:
36
  raise ValueError()
37
  if not isinstance(body['track_id'],str) or not isinstance(body['track_sha256'],str): raise ValueError()
38
- if type(body['vehicle_type']) is not int: raise ValueError()
39
  milliseconds(body['lap_seconds'])
40
  except Exception: raise HTTPException(400,'Invalid leaderboard comparison request') from None
41
  finally: data.clear()
42
- if body['vehicle_type']!=0:
43
- return {'status':'unsupported_vehicle','message':'Steam comparison is available only for Formula runs.'}
44
  entry=next((track for track in library.catalog()['tracks'] if track['id']==body['track_id']),None)
45
  if entry is None:
46
  return {'status':'unsupported_track','message':'Steam comparison is available only for supported built-in tracks.'}
@@ -49,7 +47,9 @@ def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None
49
  if not leaderboard_admission.acquire(blocking=False):
50
  return {'status':'busy','message':'Another Steam check is in progress. The completed result is unaffected.'}
51
  try:
52
- return await run_in_threadpool(compare_public_best_lap,entry,body['lap_seconds'])
 
 
53
  except SteamUnavailable as error:
54
  result={'status':'unavailable','failure_category':error.failure_category,
55
  'message':'Steam could not provide a complete public leaderboard. The completed result is unaffected.'}
 
35
  if not isinstance(body,dict) or set(body)!={'track_id','track_sha256','vehicle_type','lap_seconds'}:
36
  raise ValueError()
37
  if not isinstance(body['track_id'],str) or not isinstance(body['track_sha256'],str): raise ValueError()
38
+ if type(body['vehicle_type']) is not int or not 0<=body['vehicle_type']<=3: raise ValueError()
39
  milliseconds(body['lap_seconds'])
40
  except Exception: raise HTTPException(400,'Invalid leaderboard comparison request') from None
41
  finally: data.clear()
 
 
42
  entry=next((track for track in library.catalog()['tracks'] if track['id']==body['track_id']),None)
43
  if entry is None:
44
  return {'status':'unsupported_track','message':'Steam comparison is available only for supported built-in tracks.'}
 
47
  if not leaderboard_admission.acquire(blocking=False):
48
  return {'status':'busy','message':'Another Steam check is in progress. The completed result is unaffected.'}
49
  try:
50
+ result=await run_in_threadpool(compare_public_best_lap,entry,body['lap_seconds'])
51
+ if result.get('status')=='ok':result['vehicle_type']=body['vehicle_type']
52
+ return result
53
  except SteamUnavailable as error:
54
  result={'status':'unavailable','failure_category':error.failure_category,
55
  'message':'Steam could not provide a complete public leaderboard. The completed result is unaffected.'}
worker.py CHANGED
@@ -33,6 +33,7 @@ def read_json(data):
33
  return result
34
 
35
  OUTPUT_NAMES = ('Steering', 'Acceleration', 'Handbrake', 'Brake', 'Boost')
 
36
  SCALAR_SENSORS = {'speed', 'velocityFront', 'velocitySide', 'angularVelocity',
37
  'wheelAngle', 'boostCapacity', 'correctDirection'}
38
 
@@ -74,10 +75,16 @@ def sensor_input(sensor):
74
  def network_input(data):
75
  value=read_json(data)
76
  network=value['NeuralNetwork']; shape=network['Shape']; outputs=value.get('Outputs')
77
- if type(value.get('Type')) is not int or value['Type']!=0: raise ValueError('Formula vehicle required')
 
 
78
  if (not isinstance(outputs,list) or not 1<=len(outputs)<=5 or
79
  any(type(n) is not int or not 0<=n<5 for n in outputs) or len(set(outputs))!=len(outputs)):
80
  raise ValueError('Use an ordered unique subset of the five game outputs')
 
 
 
 
81
  if (not isinstance(shape,list) or not 2<=len(shape)<=12 or
82
  any(type(n) is not int or n<1 for n in shape) or shape[0]>20 or
83
  any(n>16 for n in shape[1:-1]) or shape[-1]!=len(outputs)):
@@ -97,7 +104,7 @@ def network_input(data):
97
  for n in [x for row in weights[i] for x in row]+biases[i]:
98
  if type(n) not in (int,float) or not math.isfinite(n) or abs(n)>1e6: raise ValueError('Weight value')
99
  return {'Id':str(uuid.uuid4()),'Stats':{'Generations':[]},'Snapshots':[],
100
- 'Type':0,'Outputs':outputs[:],'Sensors':clean_sensors,
101
  'Name':'HF candidate','NeuralNetwork':{'Shape':shape,'InputShape':shape[0],'OutputShape':shape[-1],
102
  'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
103
  'Weights':weights,'Biases':biases}}
@@ -132,6 +139,16 @@ def best_run_lap(history):
132
  laps = [v for v in values if type(v) in (int, float) and math.isfinite(v) and v > 0]
133
  return min(laps) if laps else None
134
 
 
 
 
 
 
 
 
 
 
 
135
  def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_template=None,with_report=False,gpu_library=None,config=None):
136
  started=time.perf_counter()
137
  config=validate_config(config)
@@ -139,7 +156,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
139
  # Deployment paths are supplied by trusted application configuration, never uploads.
140
  binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
141
  importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
142
- scene_template=Path(scene_template or ROOT/'assets/scenes/formula_template.json').resolve()
143
  if not all(p.is_file() for p in (binary,importer,scene_template)):
144
  raise RuntimeError('Native tools or scene template unavailable')
145
  # No inherited provider tokens, credential paths, or caller-chosen commands.
@@ -189,6 +206,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
189
  'best_lap_seconds':best_run_lap(history),'best_lap_scope':'Best completed lap observed during this run; may belong to a different car than the exported candidate','lapped_cars':last.get('lapped_cars'),
190
  'simulated_ticks':last.get('simulated_ticks'),'requested_ticks':config['ticks'],
191
  'candidate_validated':True,'execution_backend':'cuda' if gpu_library is not None else 'cpu',
 
192
  'inputs':{'track_sha256':hashlib.sha256(track_bytes).hexdigest(),'network_sha256':hashlib.sha256(network_bytes).hexdigest()},
193
  'settings':config,'history':[{'generation':i+1,'mutation':h.get('mutation_rate'),
194
  'best_score':h.get('best_score'),'mean_score':h.get('mean_score'),'best_lap_seconds':h.get('best_lap_s'),
 
33
  return result
34
 
35
  OUTPUT_NAMES = ('Steering', 'Acceleration', 'Handbrake', 'Brake', 'Boost')
36
+ VEHICLE_NAMES = ('Formula', 'Rally', 'Snowmobile', 'Truck')
37
  SCALAR_SENSORS = {'speed', 'velocityFront', 'velocitySide', 'angularVelocity',
38
  'wheelAngle', 'boostCapacity', 'correctDirection'}
39
 
 
75
  def network_input(data):
76
  value=read_json(data)
77
  network=value['NeuralNetwork']; shape=network['Shape']; outputs=value.get('Outputs')
78
+ vehicle_type=value.get('Type')
79
+ if type(vehicle_type) is not int or not 0<=vehicle_type<len(VEHICLE_NAMES):
80
+ raise ValueError('Vehicle Type must be Formula (0), Rally (1), Snowmobile (2), or Truck (3)')
81
  if (not isinstance(outputs,list) or not 1<=len(outputs)<=5 or
82
  any(type(n) is not int or not 0<=n<5 for n in outputs) or len(set(outputs))!=len(outputs)):
83
  raise ValueError('Use an ordered unique subset of the five game outputs')
84
+ if vehicle_type!=0 and not {0,1}.issubset(outputs):
85
+ raise ValueError('Rally, Snowmobile, and Truck networks require Steering and Acceleration outputs')
86
+ if vehicle_type==2 and 2 in outputs:
87
+ raise ValueError('Snowmobile Handbrake output is unavailable in the original game editor')
88
  if (not isinstance(shape,list) or not 2<=len(shape)<=12 or
89
  any(type(n) is not int or n<1 for n in shape) or shape[0]>20 or
90
  any(n>16 for n in shape[1:-1]) or shape[-1]!=len(outputs)):
 
104
  for n in [x for row in weights[i] for x in row]+biases[i]:
105
  if type(n) not in (int,float) or not math.isfinite(n) or abs(n)>1e6: raise ValueError('Weight value')
106
  return {'Id':str(uuid.uuid4()),'Stats':{'Generations':[]},'Snapshots':[],
107
+ 'Type':vehicle_type,'Outputs':outputs[:],'Sensors':clean_sensors,
108
  'Name':'HF candidate','NeuralNetwork':{'Shape':shape,'InputShape':shape[0],'OutputShape':shape[-1],
109
  'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
110
  'Weights':weights,'Biases':biases}}
 
139
  laps = [v for v in values if type(v) in (int, float) and math.isfinite(v) and v > 0]
140
  return min(laps) if laps else None
141
 
142
+ def vehicle_scene_template(scene_template, vehicle_type):
143
+ if type(vehicle_type) is not int or not 0<=vehicle_type<len(VEHICLE_NAMES):
144
+ raise ValueError('Unsupported vehicle Type')
145
+ formula=Path(scene_template or ROOT/'assets/formula_template.json').resolve()
146
+ if vehicle_type==0:return formula
147
+ name=VEHICLE_NAMES[vehicle_type].lower()
148
+ # Only the application-supplied Formula path determines the sibling asset
149
+ # directory; uploaded JSON never supplies a template path.
150
+ return (formula.parent/(name+'_template.json')).resolve()
151
+
152
  def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_template=None,with_report=False,gpu_library=None,config=None):
153
  started=time.perf_counter()
154
  config=validate_config(config)
 
156
  # Deployment paths are supplied by trusted application configuration, never uploads.
157
  binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
158
  importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
159
+ scene_template=vehicle_scene_template(scene_template,template['Type'])
160
  if not all(p.is_file() for p in (binary,importer,scene_template)):
161
  raise RuntimeError('Native tools or scene template unavailable')
162
  # No inherited provider tokens, credential paths, or caller-chosen commands.
 
206
  'best_lap_seconds':best_run_lap(history),'best_lap_scope':'Best completed lap observed during this run; may belong to a different car than the exported candidate','lapped_cars':last.get('lapped_cars'),
207
  'simulated_ticks':last.get('simulated_ticks'),'requested_ticks':config['ticks'],
208
  'candidate_validated':True,'execution_backend':'cuda' if gpu_library is not None else 'cpu',
209
+ 'vehicle_type':template['Type'],'vehicle_name':VEHICLE_NAMES[template['Type']],
210
  'inputs':{'track_sha256':hashlib.sha256(track_bytes).hexdigest(),'network_sha256':hashlib.sha256(network_bytes).hexdigest()},
211
  'settings':config,'history':[{'generation':i+1,'mutation':h.get('mutation_rate'),
212
  'best_score':h.get('best_score'),'mean_score':h.get('mean_score'),'best_lap_seconds':h.get('best_lap_s'),