Spaces:
Running on Zero
Running on Zero
Add 28 accurately labeled built-in replica tracks and synchronized selectors
Browse files- DATA_POLICY.md +10 -0
- FRONTEND_SOURCE.json +1 -1
- README.md +1 -1
- RELEASE_MANIFEST.json +39 -7
- STORAGE_BOUNDARY.md +2 -0
- TRACK_LIBRARY.md +37 -0
- builtin_tracks.py +55 -0
- builtin_tracks/catalog.json +494 -0
- builtin_tracks/tracks/Replica A01 Beginner.track +0 -0
- builtin_tracks/tracks/Replica A02 Sharp Turns.track +0 -0
- builtin_tracks/tracks/Replica A03 High Speed.track +0 -0
- builtin_tracks/tracks/Replica A04 Dirt.track +0 -0
- builtin_tracks/tracks/Replica A05 Two Terrains.track +0 -0
- builtin_tracks/tracks/Replica A06 Ice.track +0 -0
- builtin_tracks/tracks/Replica A07 Three Terrains.track +0 -0
- builtin_tracks/tracks/Replica A08 Long.track +0 -0
- builtin_tracks/tracks/Replica A09 Sharpest.track +0 -0
- builtin_tracks/tracks/Replica B01 Oval.track +0 -0
- builtin_tracks/tracks/Replica B02 Snake.track +0 -0
- builtin_tracks/tracks/Replica B03 Slalom.track +0 -0
- builtin_tracks/tracks/Replica B04 Rally.track +0 -0
- builtin_tracks/tracks/Replica B05 Racetrack.track +0 -0
- builtin_tracks/tracks/Replica B06 Hard.track +0 -0
- builtin_tracks/tracks/Replica B07 Drift.track +0 -0
- builtin_tracks/tracks/Replica B08 Arctic Circle.track +0 -0
- builtin_tracks/tracks/Replica B09 Checkered.track +0 -0
- builtin_tracks/tracks/Replica R01 Blitzring.track +0 -0
- builtin_tracks/tracks/Replica R02 Desert Rally.track +0 -0
- builtin_tracks/tracks/Replica R03 Glacier.track +0 -0
- builtin_tracks/tracks/Replica R04 Truck Maze.track +0 -0
- builtin_tracks/tracks/Replica R05 Endurance 500.track +0 -0
- builtin_tracks/tracks/Replica R06 Mix.track +0 -0
- builtin_tracks/tracks/Replica R07 Mirage Marina.track +0 -0
- builtin_tracks/tracks/Replica R08 Demolition Derby.track +0 -0
- builtin_tracks/tracks/Replica R09 Eau Noir.track +0 -0
- builtin_tracks/tracks/Replica The Champions Trial.track +0 -0
- client.js +9 -3
- index.html +83 -1
- server.py +14 -1
- track-library.js +79 -0
DATA_POLICY.md
CHANGED
|
@@ -7,6 +7,16 @@ training, analytics or public examples. Inputs remain in the browser until Run.
|
|
| 7 |
The interface supports native CPU and, on a ZeroGPU deployment, an explicitly
|
| 8 |
selected GPU job. CPU requests do not acquire a GPU lease.
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
GPU inputs await dispatch in application memory for at most 120 seconds. The
|
| 11 |
queue receives a random one-use ticket, not the uploaded track or network bytes.
|
| 12 |
Inputs are released from the pending store on dispatch, expiry or shutdown.
|
|
|
|
| 7 |
The interface supports native CPU and, on a ZeroGPU deployment, an explicitly
|
| 8 |
selected GPU job. CPU requests do not acquire a GPU lease.
|
| 9 |
|
| 10 |
+
The built-in replica track library is a separate, intentionally reusable public
|
| 11 |
+
reference collection shipped with the app. Visitors can retrieve these listed,
|
| 12 |
+
hash-checked files. They are programmatically reconstructed editor-format
|
| 13 |
+
replicas, not editor-authored or official packaged track files. Job deletion does
|
| 14 |
+
not erase this reference library; it erases only submitted job copies and job
|
| 15 |
+
results under the rules below. Custom uploaded tracks/networks are never added
|
| 16 |
+
to the library. Track selection and reference bytes may remain in this page's
|
| 17 |
+
memory across runs, but are not saved in cookies, localStorage or recipes.
|
| 18 |
+
See TRACK_LIBRARY.md in the release package for provenance and limitations.
|
| 19 |
+
|
| 20 |
GPU inputs await dispatch in application memory for at most 120 seconds. The
|
| 21 |
queue receives a random one-use ticket, not the uploaded track or network bytes.
|
| 22 |
Inputs are released from the pending store on dispatch, expiry or shutdown.
|
FRONTEND_SOURCE.json
CHANGED
|
@@ -4,5 +4,5 @@
|
|
| 4 |
"output_sha256": "135a0c57be851af2879660ae6584a4bfa0a9280fc33e2c0372bc47b531f1960f",
|
| 5 |
"scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
|
| 6 |
"status": "Local candidate: configurable training, browser recipes, bounded sequential batches, browser network editor; track renderer and star evaluation unconnected",
|
| 7 |
-
"candidate_sha256": "
|
| 8 |
}
|
|
|
|
| 4 |
"output_sha256": "135a0c57be851af2879660ae6584a4bfa0a9280fc33e2c0372bc47b531f1960f",
|
| 5 |
"scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
|
| 6 |
"status": "Local candidate: configurable training, browser recipes, bounded sequential batches, browser network editor; track renderer and star evaluation unconnected",
|
| 7 |
+
"candidate_sha256": "11237dcf43bb2744cbb83982e44fa4db35da81c24d5c0df48d896f8973bac0b5"
|
| 8 |
}
|
README.md
CHANGED
|
@@ -11,7 +11,7 @@ hf_oauth_expiration_minutes: 60
|
|
| 11 |
Protected CPU/ZeroGPU integration candidate. Custom interface with Gradio Server on port 7860.
|
| 12 |
Simulator: https://github.com/Zorro909/driving_sim_rs
|
| 13 |
Hosting adaptation and UI: TiGa https://github.com/seeker-cyber-maker/driving_sim_rs
|
| 14 |
-
CPU is the default; GPU requests explicitly use ZeroGPU. No automatic fallback.
|
| 15 |
One server process; no persistent storage. See DATA_POLICY.md for retention limits.
|
| 16 |
Not yet verified in the hosted Linux runtime; do not publish as a stable release.
|
| 17 |
|
|
|
|
| 11 |
Protected CPU/ZeroGPU integration candidate. Custom interface with Gradio Server on port 7860.
|
| 12 |
Simulator: https://github.com/Zorro909/driving_sim_rs
|
| 13 |
Hosting adaptation and UI: TiGa https://github.com/seeker-cyber-maker/driving_sim_rs
|
| 14 |
+
CPU is the default; GPU requests explicitly use ZeroGPU. No automatic fallback. 28 built-in editor-format replica tracks; no bundled networks. See TRACK_LIBRARY.md for provenance and limitations.
|
| 15 |
One server process; no persistent storage. See DATA_POLICY.md for retention limits.
|
| 16 |
Not yet verified in the hosted Linux runtime; do not publish as a stable release.
|
| 17 |
|
RELEASE_MANIFEST.json
CHANGED
|
@@ -2,27 +2,59 @@
|
|
| 2 |
"backend": "cpu+zerogpu",
|
| 3 |
"files": {
|
| 4 |
"BETA_TESTING.md": "d511965b9d675a092571f8815348da991ef1ef6be3766266c1f98ff393fd3a4d",
|
| 5 |
-
"DATA_POLICY.md": "
|
| 6 |
-
"FRONTEND_SOURCE.json": "
|
| 7 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 8 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 9 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 10 |
-
"README.md": "
|
| 11 |
-
"STORAGE_BOUNDARY.md": "
|
|
|
|
| 12 |
"app.py": "704f789a41846b0a5bc1d3f6f5305d7ac5a6b1719ff77c23585b89fd3e68d55d",
|
| 13 |
"app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
|
| 14 |
"assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
|
| 15 |
"bin/altd-sim": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
|
| 16 |
"bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
|
| 17 |
"bin/libaltd_gpu.so": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
|
| 18 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
"delivery.py": "4f5a4e45df92e5cbfdef6eb449ede9ba26217fe24da376fafddae5cbbb73847a",
|
| 20 |
"gpu_tickets.py": "c32cb5de751d49d3e1cd970c7d6328a42ebe71602dd9fd3788c872eef42611da",
|
| 21 |
"hf-auth.js": "743fa2b62c611fcc6064664691e133efb5d163412955b2a9d0a562a428412864",
|
| 22 |
"hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
|
| 23 |
-
"index.html": "
|
| 24 |
"requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
|
| 25 |
-
"server.py": "
|
|
|
|
| 26 |
"training_config.py": "2b9768876fdc60b16afb45b98023c6c31666e30f7c56f1292f6071775e6da0c5",
|
| 27 |
"vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
|
| 28 |
"vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
|
|
|
|
| 2 |
"backend": "cpu+zerogpu",
|
| 3 |
"files": {
|
| 4 |
"BETA_TESTING.md": "d511965b9d675a092571f8815348da991ef1ef6be3766266c1f98ff393fd3a4d",
|
| 5 |
+
"DATA_POLICY.md": "1434ac5420a611b35c69da90bbbb70abb088754fdab0354a51f0f892b4abe224",
|
| 6 |
+
"FRONTEND_SOURCE.json": "e49a81a9ea37fb6724eaeac9630af249b721b983ed38e1f395d6c4db6fda0834",
|
| 7 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 8 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 9 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 10 |
+
"README.md": "5157c28039004afb7a6ef40a5f5bc27ba431f16efd7d1d2482e9bdf34373f8fe",
|
| 11 |
+
"STORAGE_BOUNDARY.md": "cf6f4b6824f0780766a5c3a44e372e6e9b1cf7d73428cc14770af7ed5ade5d45",
|
| 12 |
+
"TRACK_LIBRARY.md": "7e4829c5e0933bfb317c21d7441ad0ba2ee00ab7f9f1635549452d504aa0777b",
|
| 13 |
"app.py": "704f789a41846b0a5bc1d3f6f5305d7ac5a6b1719ff77c23585b89fd3e68d55d",
|
| 14 |
"app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
|
| 15 |
"assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
|
| 16 |
"bin/altd-sim": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
|
| 17 |
"bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
|
| 18 |
"bin/libaltd_gpu.so": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
|
| 19 |
+
"builtin_tracks.py": "2ecc2b1d00fe15701b0271d71e1e68d2e7e59c596330879494055f9b2a99c242",
|
| 20 |
+
"builtin_tracks/catalog.json": "65006e70a87a5a53e3738166b0895bc4db9f99767dd891d917b68029abb4e80a",
|
| 21 |
+
"builtin_tracks/tracks/Replica A01 Beginner.track": "ca5749537450430794e2eade2e0ac72fa141a4f225e13e2f8ef842abb948ff15",
|
| 22 |
+
"builtin_tracks/tracks/Replica A02 Sharp Turns.track": "097f1ea8edf041112b690d0638075630716ddc03c7d0b1980ddcbeaf5071c8d4",
|
| 23 |
+
"builtin_tracks/tracks/Replica A03 High Speed.track": "88917c63847be1854b989bb28a23af7eeacb964c3e7df9579953aebc9496e6af",
|
| 24 |
+
"builtin_tracks/tracks/Replica A04 Dirt.track": "7f4fe58516227b15898d14bb0abb9a0856126d24fcd793884f051f7a4fae521d",
|
| 25 |
+
"builtin_tracks/tracks/Replica A05 Two Terrains.track": "c4ee2842920d99cdfe3eebdcad59a77e24b626380acef0d02a39ea1e23823e2a",
|
| 26 |
+
"builtin_tracks/tracks/Replica A06 Ice.track": "fccb9a159a06d1b986c6fe7d5bb89c0cabad3a005531f4e0d71f6e37254ada34",
|
| 27 |
+
"builtin_tracks/tracks/Replica A07 Three Terrains.track": "a8fa652ad451e2702a23d5f3429eb0b6a6408bf6a2a76a73d549023e481875c6",
|
| 28 |
+
"builtin_tracks/tracks/Replica A08 Long.track": "3e259bd227776ca847d35baaea88b5e8af57cc920643bf71563176bd6554ad65",
|
| 29 |
+
"builtin_tracks/tracks/Replica A09 Sharpest.track": "5362cea3c564dce8f4f22fcd4b798347931dfaa4e65b84624944952b3e0b0d2a",
|
| 30 |
+
"builtin_tracks/tracks/Replica B01 Oval.track": "0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158",
|
| 31 |
+
"builtin_tracks/tracks/Replica B02 Snake.track": "210e699b1fa5f2624a2ff0969b73a20af7bc56bf774f4fd282f6109f80bfdb3c",
|
| 32 |
+
"builtin_tracks/tracks/Replica B03 Slalom.track": "a8bab86f93e3072bf27a81a354220c137207b9fc0b548372c8dab93639a18a24",
|
| 33 |
+
"builtin_tracks/tracks/Replica B04 Rally.track": "9d2fc668a7c86aabb9ca9dbfdbd21dff0d099c5d77029aa2ae96b6c7b9efd3f0",
|
| 34 |
+
"builtin_tracks/tracks/Replica B05 Racetrack.track": "d0804ebc17646d2f7c3be65cfe0f6e94033417e75b101a8c598a69131a170079",
|
| 35 |
+
"builtin_tracks/tracks/Replica B06 Hard.track": "8b1a10fd8485405d7f73abca8890f4845145227177c9ac07ac9a1d79f28908f9",
|
| 36 |
+
"builtin_tracks/tracks/Replica B07 Drift.track": "d6d46216882cb63d55b1e8ce81ffa67f1c95ffd0a86a72806b8fd23973c6ce0a",
|
| 37 |
+
"builtin_tracks/tracks/Replica B08 Arctic Circle.track": "229128e86a87089f781b072a4c677ff729cf8488b1d74ad75cfb43655b9f4a16",
|
| 38 |
+
"builtin_tracks/tracks/Replica B09 Checkered.track": "bec4dbd0edc35e0e4f4d1035c608a0c56bbc99e7301f640f8e2eddba0100b2fe",
|
| 39 |
+
"builtin_tracks/tracks/Replica R01 Blitzring.track": "14b52a7cbbf7de5606c772c74730c0e8776f39ed72955fef5ae1f7c2d8ccef77",
|
| 40 |
+
"builtin_tracks/tracks/Replica R02 Desert Rally.track": "653286b00f2f04450e698d8b8e9d4ecb268064b323b182d2de9db7d017b22238",
|
| 41 |
+
"builtin_tracks/tracks/Replica R03 Glacier.track": "0e1b42ce51ae91a8702e173013a090d00145e518bb47d7a659cb1d1fdff011b5",
|
| 42 |
+
"builtin_tracks/tracks/Replica R04 Truck Maze.track": "d7b89d64e118506e6cec259057886d9267ca4c6fab570e7ba0d6641e8f822f11",
|
| 43 |
+
"builtin_tracks/tracks/Replica R05 Endurance 500.track": "dde36ad5f627bce65d45a96d46a68497f8d446f6011c9df19ee51ce71375cba8",
|
| 44 |
+
"builtin_tracks/tracks/Replica R06 Mix.track": "9de8d912a59001ea13baa7f1b4f92884b8cddf91978f31e19f3237975713f739",
|
| 45 |
+
"builtin_tracks/tracks/Replica R07 Mirage Marina.track": "8c6764f3accb1a8372d910d57f4f681572dd40c590c4a3d03517379bb360fcd7",
|
| 46 |
+
"builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 47 |
+
"builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 48 |
+
"builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 49 |
+
"client.js": "1c5446c6d192c3da25d370aba88d94f685af94acb175f2d4f5499bfa4098a628",
|
| 50 |
"delivery.py": "4f5a4e45df92e5cbfdef6eb449ede9ba26217fe24da376fafddae5cbbb73847a",
|
| 51 |
"gpu_tickets.py": "c32cb5de751d49d3e1cd970c7d6328a42ebe71602dd9fd3788c872eef42611da",
|
| 52 |
"hf-auth.js": "743fa2b62c611fcc6064664691e133efb5d163412955b2a9d0a562a428412864",
|
| 53 |
"hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
|
| 54 |
+
"index.html": "11237dcf43bb2744cbb83982e44fa4db35da81c24d5c0df48d896f8973bac0b5",
|
| 55 |
"requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
|
| 56 |
+
"server.py": "dd9d2e709ea61b6a3e3942be8377f0cad12509d4df3dbe0baa930523c0a3120c",
|
| 57 |
+
"track-library.js": "d19e2a58442e07d0d5029fbdfae1461106b2c3fe91dcb7b3091e304fc700811a",
|
| 58 |
"training_config.py": "2b9768876fdc60b16afb45b98023c6c31666e30f7c56f1292f6071775e6da0c5",
|
| 59 |
"vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
|
| 60 |
"vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
|
STORAGE_BOUNDARY.md
CHANGED
|
@@ -7,6 +7,8 @@ same settings contract is used independently of the selected storage policy.
|
|
| 7 |
|---|---|---|
|
| 8 |
| Recipe library | Injected storage adapter, browser localStorage | Explicit save; own-key clear; settings/names/references only |
|
| 9 |
| Track / network editor | Browser File/Blob objects | Page memory; selected for upload only on Start |
|
|
|
|
|
|
|
| 10 |
| Worker inputs / intermediate files | Temporary directory | Removed before successful result publication |
|
| 11 |
| GPU pending inputs | Opaque single-use ticket plus memory store | Dispatch, fixed 120-second expiry, or shutdown |
|
| 12 |
| Single-run output | Memory result store and random job key | Receipt ACK in automatic mode, manual delete, fixed 30-minute expiry, or shutdown |
|
|
|
|
| 7 |
|---|---|---|
|
| 8 |
| Recipe library | Injected storage adapter, browser localStorage | Explicit save; own-key clear; settings/names/references only |
|
| 9 |
| Track / network editor | Browser File/Blob objects | Page memory; selected for upload only on Start |
|
| 10 |
+
| Built-in replica library | Read-only, allow-listed release files; anonymous catalog/file endpoints | Intentionally persistent shared references; not erased by job deletion; user uploads never enter the catalog |
|
| 11 |
+
| Selected built-in track | Synchronized selectors and one verified Blob | Page memory across runs; no cookie, recipe or localStorage persistence |
|
| 12 |
| Worker inputs / intermediate files | Temporary directory | Removed before successful result publication |
|
| 13 |
| GPU pending inputs | Opaque single-use ticket plus memory store | Dispatch, fixed 120-second expiry, or shutdown |
|
| 14 |
| Single-run output | Memory result store and random job key | Receipt ACK in automatic mode, manual delete, fixed 30-minute expiry, or shutdown |
|
TRACK_LIBRARY.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Built-in editor-format replica tracks
|
| 2 |
+
|
| 3 |
+
This read-only library contains 28 programmatically reconstructed editor-format
|
| 4 |
+
replicas: A01–A09, B01–B09, R01–R09 and The Champions Trial. The operator explicitly
|
| 5 |
+
approved this replica bundle for inclusion. The files are not editor-authored,
|
| 6 |
+
clean-room creations or the original packaged track files. Original layout data
|
| 7 |
+
was used; a new file format/serialization is not a claim of independent origin.
|
| 8 |
+
|
| 9 |
+
Source schema: ald-editor-format-replicas-v1, run-r2-dummy-stars. The shipped
|
| 10 |
+
catalog declares the method and editor_authored=false / clean_room=false, and
|
| 11 |
+
contains each file's SHA-256 and byte count. Private provenance paths, original
|
| 12 |
+
packaged files, artwork, textures, opponents/controllers, original race parameters
|
| 13 |
+
and the native geometry catalog are not part of this library.
|
| 14 |
+
|
| 15 |
+
Training-track numeric challenge conditions were preserved. Race replicas use
|
| 16 |
+
dummy lap stars rather than claiming to reproduce opponent challenges. The HF
|
| 17 |
+
worker does not evaluate these conditions or grant campaign stars. Availability
|
| 18 |
+
in this selector is not a claim of official game approval, legal clearance,
|
| 19 |
+
game-editor load verification, physics parity or leaderboard qualification.
|
| 20 |
+
|
| 21 |
+
Track selection and Training track are synchronized controls for one active
|
| 22 |
+
input. Upload a custom track remains available. Selecting a built-in clears the
|
| 23 |
+
custom file selection; choosing an upload switches back to upload mode. Built-in
|
| 24 |
+
selection survives completed runs in this page, but is not written to cookies,
|
| 25 |
+
localStorage, recipes, or account storage. Network selection is still explicit.
|
| 26 |
+
The renderer remains a placeholder.
|
| 27 |
+
|
| 28 |
+
The public app exposes only catalog-listed IDs and hash-checked replica bytes.
|
| 29 |
+
No directory browsing, caller-selected paths, remote track URLs or extraction
|
| 30 |
+
from game binaries is supported. CPU and GPU use the same existing bounded input
|
| 31 |
+
contract. Client and server both check reference-file size/SHA-256.
|
| 32 |
+
|
| 33 |
+
These reusable reference tracks are intentionally part of the app package, not
|
| 34 |
+
private job data. Job deletion removes the submitted copies, temporary work and
|
| 35 |
+
stored result, not this shared library. Built-in files are retrievable by app
|
| 36 |
+
visitors even while HF source visibility remains Protected. User-uploaded
|
| 37 |
+
tracks/networks never enter this catalog and retain the existing deletion rules.
|
builtin_tracks.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Read-only, hash-checked reference tracks; separate from ephemeral job data."""
|
| 2 |
+
import hashlib
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class TrackLibrary:
|
| 9 |
+
def __init__(self, root):
|
| 10 |
+
self.root=Path(root).resolve()
|
| 11 |
+
self._entries={}
|
| 12 |
+
catalog=self.root/'catalog.json'
|
| 13 |
+
if not catalog.exists():return # Older/local upload-only installations.
|
| 14 |
+
if catalog.stat().st_size>256*1024:raise ValueError('Track catalog too large')
|
| 15 |
+
data=json.loads(catalog.read_text())
|
| 16 |
+
if data.get('schema')!='ald-editor-format-replicas-v1':raise ValueError('Unknown track catalog')
|
| 17 |
+
tracks=data['tracks']
|
| 18 |
+
if not isinstance(tracks,list) or not 1<=len(tracks)<=128:raise ValueError('Track count')
|
| 19 |
+
for entry in tracks:
|
| 20 |
+
identifier=entry['id'];relative=Path(entry['file'])
|
| 21 |
+
if not isinstance(identifier,str) or not re.fullmatch(r'[a-z0-9-]{1,80}',identifier):
|
| 22 |
+
raise ValueError('Track ID')
|
| 23 |
+
if identifier in self._entries:raise ValueError('Duplicate track ID')
|
| 24 |
+
if len(relative.parts)!=2 or relative.parts[0]!='tracks' or relative.suffix!='.track':
|
| 25 |
+
raise ValueError('Track path')
|
| 26 |
+
path=self.root/relative
|
| 27 |
+
if path.is_symlink() or path.resolve()!=path or not path.is_file():raise ValueError('Track path')
|
| 28 |
+
size=entry['bytes'];digest=entry['sha256']
|
| 29 |
+
if type(size)!=int or not 1<=size<=1024*1024 or not re.fullmatch(r'[a-f0-9]{64}',digest):
|
| 30 |
+
raise ValueError('Track size/hash')
|
| 31 |
+
for label in ('display_name','reference_label'):
|
| 32 |
+
if not isinstance(entry[label],str) or not 1<=len(entry[label])<=100:raise ValueError('Track label')
|
| 33 |
+
public={key:entry[key] for key in ('id','display_name','reference_label','bytes','sha256')}
|
| 34 |
+
self._entries[identifier]=(path,public)
|
| 35 |
+
self.read(identifier)
|
| 36 |
+
|
| 37 |
+
def catalog(self):
|
| 38 |
+
# Never expose private provenance source paths or arbitrary input fields.
|
| 39 |
+
return {'schema':'ald-builtin-track-library-v1',
|
| 40 |
+
'method':'programmatically reconstructed editor-format replicas',
|
| 41 |
+
'editor_authored':False,'clean_room':False,
|
| 42 |
+
'challenge_runtime_status':'not evaluated by this app',
|
| 43 |
+
'tracks':[dict(entry) for _,entry in self._entries.values()]}
|
| 44 |
+
|
| 45 |
+
def read(self, identifier):
|
| 46 |
+
if identifier not in self._entries:raise KeyError(identifier)
|
| 47 |
+
path,entry=self._entries[identifier]
|
| 48 |
+
if path.is_symlink() or path.resolve()!=path or path.stat().st_size!=entry['bytes']:
|
| 49 |
+
raise ValueError('Track validation failed')
|
| 50 |
+
payload=path.read_bytes()
|
| 51 |
+
if hashlib.sha256(payload).hexdigest()!=entry['sha256']:raise ValueError('Track validation failed')
|
| 52 |
+
return payload
|
| 53 |
+
|
| 54 |
+
def members(self):
|
| 55 |
+
return [(path.relative_to(self.root).as_posix(),path) for path,_ in self._entries.values()]
|
builtin_tracks/catalog.json
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema": "ald-editor-format-replicas-v1",
|
| 3 |
+
"method": "programmatically reconstructed from private original layout data",
|
| 4 |
+
"editor_authored": false,
|
| 5 |
+
"clean_room": false,
|
| 6 |
+
"original_packaged_track_files_included": false,
|
| 7 |
+
"artwork_or_opponent_controllers_included": false,
|
| 8 |
+
"original_race_parameters_included": false,
|
| 9 |
+
"native_geometry_catalog_included": false,
|
| 10 |
+
"integration_status": "local_input_and_native_import_verified_not_deployed",
|
| 11 |
+
"challenge_runtime_status": "definitions_transferred_not_evaluated_by_current_HF_worker",
|
| 12 |
+
"tracks": [
|
| 13 |
+
{
|
| 14 |
+
"file": "tracks/Replica A01 Beginner.track",
|
| 15 |
+
"display_name": "Replica A01 Beginner",
|
| 16 |
+
"reference_label": "A01 Beginner",
|
| 17 |
+
"id": "2be5df89-4743-5df8-bf8e-34381cd5e65a",
|
| 18 |
+
"tile_count": 8,
|
| 19 |
+
"challenge_count": 3,
|
| 20 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 21 |
+
"original_campaign_unlock_stars": 0,
|
| 22 |
+
"sha256": "ca5749537450430794e2eade2e0ac72fa141a4f225e13e2f8ef842abb948ff15",
|
| 23 |
+
"bytes": 453,
|
| 24 |
+
"expanded_bytes": 1349,
|
| 25 |
+
"native_scene_equal_to_reference_layout": true,
|
| 26 |
+
"game_editor_load_verified": false
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"file": "tracks/Replica A02 Sharp Turns.track",
|
| 30 |
+
"display_name": "Replica A02 Sharp Turns",
|
| 31 |
+
"reference_label": "A02 Sharp Turns",
|
| 32 |
+
"id": "ffb40946-a112-528e-b08f-d892a0b9b2a1",
|
| 33 |
+
"tile_count": 8,
|
| 34 |
+
"challenge_count": 3,
|
| 35 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 36 |
+
"original_campaign_unlock_stars": 0,
|
| 37 |
+
"sha256": "097f1ea8edf041112b690d0638075630716ddc03c7d0b1980ddcbeaf5071c8d4",
|
| 38 |
+
"bytes": 465,
|
| 39 |
+
"expanded_bytes": 1379,
|
| 40 |
+
"native_scene_equal_to_reference_layout": true,
|
| 41 |
+
"game_editor_load_verified": false
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
"file": "tracks/Replica A03 High Speed.track",
|
| 45 |
+
"display_name": "Replica A03 High Speed",
|
| 46 |
+
"reference_label": "A03 High Speed",
|
| 47 |
+
"id": "d3bcd33c-09d4-5783-8110-85ea7cb3fa94",
|
| 48 |
+
"tile_count": 14,
|
| 49 |
+
"challenge_count": 3,
|
| 50 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 51 |
+
"original_campaign_unlock_stars": 0,
|
| 52 |
+
"sha256": "88917c63847be1854b989bb28a23af7eeacb964c3e7df9579953aebc9496e6af",
|
| 53 |
+
"bytes": 528,
|
| 54 |
+
"expanded_bytes": 2041,
|
| 55 |
+
"native_scene_equal_to_reference_layout": true,
|
| 56 |
+
"game_editor_load_verified": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"file": "tracks/Replica A04 Dirt.track",
|
| 60 |
+
"display_name": "Replica A04 Dirt",
|
| 61 |
+
"reference_label": "A04 Dirt",
|
| 62 |
+
"id": "ed26fc72-beb3-54e0-999a-78b840fe13ba",
|
| 63 |
+
"tile_count": 12,
|
| 64 |
+
"challenge_count": 3,
|
| 65 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 66 |
+
"original_campaign_unlock_stars": 0,
|
| 67 |
+
"sha256": "7f4fe58516227b15898d14bb0abb9a0856126d24fcd793884f051f7a4fae521d",
|
| 68 |
+
"bytes": 547,
|
| 69 |
+
"expanded_bytes": 1863,
|
| 70 |
+
"native_scene_equal_to_reference_layout": true,
|
| 71 |
+
"game_editor_load_verified": false
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"file": "tracks/Replica A05 Two Terrains.track",
|
| 75 |
+
"display_name": "Replica A05 Two Terrains",
|
| 76 |
+
"reference_label": "A05 Two Terrains",
|
| 77 |
+
"id": "06781f37-be14-5dfb-92fa-4f77e29607d9",
|
| 78 |
+
"tile_count": 16,
|
| 79 |
+
"challenge_count": 3,
|
| 80 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 81 |
+
"original_campaign_unlock_stars": 0,
|
| 82 |
+
"sha256": "c4ee2842920d99cdfe3eebdcad59a77e24b626380acef0d02a39ea1e23823e2a",
|
| 83 |
+
"bytes": 567,
|
| 84 |
+
"expanded_bytes": 2261,
|
| 85 |
+
"native_scene_equal_to_reference_layout": true,
|
| 86 |
+
"game_editor_load_verified": false
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"file": "tracks/Replica A06 Ice.track",
|
| 90 |
+
"display_name": "Replica A06 Ice",
|
| 91 |
+
"reference_label": "A06 Ice",
|
| 92 |
+
"id": "16801fef-ba6a-5ea6-aab0-d191e3ceecf4",
|
| 93 |
+
"tile_count": 10,
|
| 94 |
+
"challenge_count": 3,
|
| 95 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 96 |
+
"original_campaign_unlock_stars": 0,
|
| 97 |
+
"sha256": "fccb9a159a06d1b986c6fe7d5bb89c0cabad3a005531f4e0d71f6e37254ada34",
|
| 98 |
+
"bytes": 508,
|
| 99 |
+
"expanded_bytes": 1661,
|
| 100 |
+
"native_scene_equal_to_reference_layout": true,
|
| 101 |
+
"game_editor_load_verified": false
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"file": "tracks/Replica A07 Three Terrains.track",
|
| 105 |
+
"display_name": "Replica A07 Three Terrains",
|
| 106 |
+
"reference_label": "A07 Three Terrains",
|
| 107 |
+
"id": "5c4aaf13-b594-5ec3-b836-efec5fab7887",
|
| 108 |
+
"tile_count": 12,
|
| 109 |
+
"challenge_count": 3,
|
| 110 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 111 |
+
"original_campaign_unlock_stars": 0,
|
| 112 |
+
"sha256": "a8fa652ad451e2702a23d5f3429eb0b6a6408bf6a2a76a73d549023e481875c6",
|
| 113 |
+
"bytes": 533,
|
| 114 |
+
"expanded_bytes": 1858,
|
| 115 |
+
"native_scene_equal_to_reference_layout": true,
|
| 116 |
+
"game_editor_load_verified": false
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"file": "tracks/Replica A08 Long.track",
|
| 120 |
+
"display_name": "Replica A08 Long",
|
| 121 |
+
"reference_label": "A08 Long",
|
| 122 |
+
"id": "1a18c7cc-f0fd-5055-9799-2a4abde8fed3",
|
| 123 |
+
"tile_count": 36,
|
| 124 |
+
"challenge_count": 3,
|
| 125 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 126 |
+
"original_campaign_unlock_stars": 0,
|
| 127 |
+
"sha256": "3e259bd227776ca847d35baaea88b5e8af57cc920643bf71563176bd6554ad65",
|
| 128 |
+
"bytes": 683,
|
| 129 |
+
"expanded_bytes": 4140,
|
| 130 |
+
"native_scene_equal_to_reference_layout": true,
|
| 131 |
+
"game_editor_load_verified": false
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"file": "tracks/Replica A09 Sharpest.track",
|
| 135 |
+
"display_name": "Replica A09 Sharpest",
|
| 136 |
+
"reference_label": "A09 Sharpest",
|
| 137 |
+
"id": "9328cb63-d50c-57c3-972b-6bcb9ab475a9",
|
| 138 |
+
"tile_count": 16,
|
| 139 |
+
"challenge_count": 3,
|
| 140 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 141 |
+
"original_campaign_unlock_stars": 0,
|
| 142 |
+
"sha256": "5362cea3c564dce8f4f22fcd4b798347931dfaa4e65b84624944952b3e0b0d2a",
|
| 143 |
+
"bytes": 584,
|
| 144 |
+
"expanded_bytes": 2259,
|
| 145 |
+
"native_scene_equal_to_reference_layout": true,
|
| 146 |
+
"game_editor_load_verified": false
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"file": "tracks/Replica B01 Oval.track",
|
| 150 |
+
"display_name": "Replica B01 Oval",
|
| 151 |
+
"reference_label": "B01 Oval",
|
| 152 |
+
"id": "787f73f5-3b8c-5d95-b0e3-0016ed076970",
|
| 153 |
+
"tile_count": 6,
|
| 154 |
+
"challenge_count": 3,
|
| 155 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 156 |
+
"original_campaign_unlock_stars": 0,
|
| 157 |
+
"sha256": "0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158",
|
| 158 |
+
"bytes": 477,
|
| 159 |
+
"expanded_bytes": 1291,
|
| 160 |
+
"native_scene_equal_to_reference_layout": true,
|
| 161 |
+
"game_editor_load_verified": false
|
| 162 |
+
},
|
| 163 |
+
{
|
| 164 |
+
"file": "tracks/Replica B02 Snake.track",
|
| 165 |
+
"display_name": "Replica B02 Snake",
|
| 166 |
+
"reference_label": "B02 Snake",
|
| 167 |
+
"id": "e2358ccd-201e-570c-9f61-ce0994c71935",
|
| 168 |
+
"tile_count": 14,
|
| 169 |
+
"challenge_count": 3,
|
| 170 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 171 |
+
"original_campaign_unlock_stars": 0,
|
| 172 |
+
"sha256": "210e699b1fa5f2624a2ff0969b73a20af7bc56bf774f4fd282f6109f80bfdb3c",
|
| 173 |
+
"bytes": 555,
|
| 174 |
+
"expanded_bytes": 2064,
|
| 175 |
+
"native_scene_equal_to_reference_layout": true,
|
| 176 |
+
"game_editor_load_verified": false
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"file": "tracks/Replica B03 Slalom.track",
|
| 180 |
+
"display_name": "Replica B03 Slalom",
|
| 181 |
+
"reference_label": "B03 Slalom",
|
| 182 |
+
"id": "04da6fdb-0330-57d5-920f-3001dfe4b8c0",
|
| 183 |
+
"tile_count": 14,
|
| 184 |
+
"challenge_count": 3,
|
| 185 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 186 |
+
"original_campaign_unlock_stars": 0,
|
| 187 |
+
"sha256": "a8bab86f93e3072bf27a81a354220c137207b9fc0b548372c8dab93639a18a24",
|
| 188 |
+
"bytes": 530,
|
| 189 |
+
"expanded_bytes": 2077,
|
| 190 |
+
"native_scene_equal_to_reference_layout": true,
|
| 191 |
+
"game_editor_load_verified": false
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"file": "tracks/Replica B04 Rally.track",
|
| 195 |
+
"display_name": "Replica B04 Rally",
|
| 196 |
+
"reference_label": "B04 Rally",
|
| 197 |
+
"id": "a0be65c0-4142-5d43-b00e-63f56e640d48",
|
| 198 |
+
"tile_count": 20,
|
| 199 |
+
"challenge_count": 3,
|
| 200 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 201 |
+
"original_campaign_unlock_stars": 0,
|
| 202 |
+
"sha256": "9d2fc668a7c86aabb9ca9dbfdbd21dff0d099c5d77029aa2ae96b6c7b9efd3f0",
|
| 203 |
+
"bytes": 648,
|
| 204 |
+
"expanded_bytes": 2743,
|
| 205 |
+
"native_scene_equal_to_reference_layout": true,
|
| 206 |
+
"game_editor_load_verified": false
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"file": "tracks/Replica B05 Racetrack.track",
|
| 210 |
+
"display_name": "Replica B05 Racetrack",
|
| 211 |
+
"reference_label": "B05 Racetrack",
|
| 212 |
+
"id": "7a62028b-e2eb-59db-81a0-8e5933f2a09d",
|
| 213 |
+
"tile_count": 22,
|
| 214 |
+
"challenge_count": 3,
|
| 215 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 216 |
+
"original_campaign_unlock_stars": 0,
|
| 217 |
+
"sha256": "d0804ebc17646d2f7c3be65cfe0f6e94033417e75b101a8c598a69131a170079",
|
| 218 |
+
"bytes": 627,
|
| 219 |
+
"expanded_bytes": 2884,
|
| 220 |
+
"native_scene_equal_to_reference_layout": true,
|
| 221 |
+
"game_editor_load_verified": false
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"file": "tracks/Replica B06 Hard.track",
|
| 225 |
+
"display_name": "Replica B06 Hard",
|
| 226 |
+
"reference_label": "B06 Hard",
|
| 227 |
+
"id": "251fb67e-1f1e-537e-8c85-c3688f08198f",
|
| 228 |
+
"tile_count": 30,
|
| 229 |
+
"challenge_count": 3,
|
| 230 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 231 |
+
"original_campaign_unlock_stars": 0,
|
| 232 |
+
"sha256": "8b1a10fd8485405d7f73abca8890f4845145227177c9ac07ac9a1d79f28908f9",
|
| 233 |
+
"bytes": 674,
|
| 234 |
+
"expanded_bytes": 3625,
|
| 235 |
+
"native_scene_equal_to_reference_layout": true,
|
| 236 |
+
"game_editor_load_verified": false
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"file": "tracks/Replica B07 Drift.track",
|
| 240 |
+
"display_name": "Replica B07 Drift",
|
| 241 |
+
"reference_label": "B07 Drift",
|
| 242 |
+
"id": "dfef0a18-46ac-5ece-9956-b5c843e9d588",
|
| 243 |
+
"tile_count": 16,
|
| 244 |
+
"challenge_count": 3,
|
| 245 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 246 |
+
"original_campaign_unlock_stars": 0,
|
| 247 |
+
"sha256": "d6d46216882cb63d55b1e8ce81ffa67f1c95ffd0a86a72806b8fd23973c6ce0a",
|
| 248 |
+
"bytes": 570,
|
| 249 |
+
"expanded_bytes": 2282,
|
| 250 |
+
"native_scene_equal_to_reference_layout": true,
|
| 251 |
+
"game_editor_load_verified": false
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"file": "tracks/Replica B08 Arctic Circle.track",
|
| 255 |
+
"display_name": "Replica B08 Arctic Circle",
|
| 256 |
+
"reference_label": "B08 Arctic Circle",
|
| 257 |
+
"id": "8b60d3b0-d694-592e-a85b-1d77d3fe7c0f",
|
| 258 |
+
"tile_count": 28,
|
| 259 |
+
"challenge_count": 3,
|
| 260 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 261 |
+
"original_campaign_unlock_stars": 0,
|
| 262 |
+
"sha256": "229128e86a87089f781b072a4c677ff729cf8488b1d74ad75cfb43655b9f4a16",
|
| 263 |
+
"bytes": 709,
|
| 264 |
+
"expanded_bytes": 3519,
|
| 265 |
+
"native_scene_equal_to_reference_layout": true,
|
| 266 |
+
"game_editor_load_verified": false
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"file": "tracks/Replica B09 Checkered.track",
|
| 270 |
+
"display_name": "Replica B09 Checkered",
|
| 271 |
+
"reference_label": "B09 Checkered",
|
| 272 |
+
"id": "61561797-8ffb-5521-a607-b5fdfca94783",
|
| 273 |
+
"tile_count": 48,
|
| 274 |
+
"challenge_count": 3,
|
| 275 |
+
"challenge_source": "preserved_numeric_conditions",
|
| 276 |
+
"original_campaign_unlock_stars": 0,
|
| 277 |
+
"sha256": "bec4dbd0edc35e0e4f4d1035c608a0c56bbc99e7301f640f8e2eddba0100b2fe",
|
| 278 |
+
"bytes": 810,
|
| 279 |
+
"expanded_bytes": 5421,
|
| 280 |
+
"native_scene_equal_to_reference_layout": true,
|
| 281 |
+
"game_editor_load_verified": false
|
| 282 |
+
},
|
| 283 |
+
{
|
| 284 |
+
"file": "tracks/Replica R01 Blitzring.track",
|
| 285 |
+
"display_name": "Replica R01 Blitzring",
|
| 286 |
+
"reference_label": "R01 Blitzring",
|
| 287 |
+
"id": "31fc3eb7-f2cc-5e4e-9fbf-c02f8e040ff7",
|
| 288 |
+
"tile_count": 18,
|
| 289 |
+
"challenge_count": 3,
|
| 290 |
+
"challenge_source": "dummy_lap_challenges",
|
| 291 |
+
"original_campaign_unlock_stars": 0,
|
| 292 |
+
"sha256": "14b52a7cbbf7de5606c772c74730c0e8776f39ed72955fef5ae1f7c2d8ccef77",
|
| 293 |
+
"bytes": 518,
|
| 294 |
+
"expanded_bytes": 2316,
|
| 295 |
+
"native_scene_equal_to_reference_layout": true,
|
| 296 |
+
"game_editor_load_verified": false,
|
| 297 |
+
"dummy_lap_counts": [
|
| 298 |
+
1,
|
| 299 |
+
2,
|
| 300 |
+
3
|
| 301 |
+
],
|
| 302 |
+
"original_race_behavior_included": false
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"file": "tracks/Replica R02 Desert Rally.track",
|
| 306 |
+
"display_name": "Replica R02 Desert Rally",
|
| 307 |
+
"reference_label": "R02 Desert Rally",
|
| 308 |
+
"id": "17d76866-6c6b-5b04-aaa5-32a03a61183b",
|
| 309 |
+
"tile_count": 22,
|
| 310 |
+
"challenge_count": 3,
|
| 311 |
+
"challenge_source": "dummy_lap_challenges",
|
| 312 |
+
"original_campaign_unlock_stars": 0,
|
| 313 |
+
"sha256": "653286b00f2f04450e698d8b8e9d4ecb268064b323b182d2de9db7d017b22238",
|
| 314 |
+
"bytes": 552,
|
| 315 |
+
"expanded_bytes": 2750,
|
| 316 |
+
"native_scene_equal_to_reference_layout": true,
|
| 317 |
+
"game_editor_load_verified": false,
|
| 318 |
+
"dummy_lap_counts": [
|
| 319 |
+
1,
|
| 320 |
+
2,
|
| 321 |
+
3
|
| 322 |
+
],
|
| 323 |
+
"original_race_behavior_included": false
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"file": "tracks/Replica R03 Glacier.track",
|
| 327 |
+
"display_name": "Replica R03 Glacier",
|
| 328 |
+
"reference_label": "R03 Glacier",
|
| 329 |
+
"id": "2377f26c-1aff-5a32-bda4-27582a7bc62e",
|
| 330 |
+
"tile_count": 14,
|
| 331 |
+
"challenge_count": 3,
|
| 332 |
+
"challenge_source": "dummy_lap_challenges",
|
| 333 |
+
"original_campaign_unlock_stars": 0,
|
| 334 |
+
"sha256": "0e1b42ce51ae91a8702e173013a090d00145e518bb47d7a659cb1d1fdff011b5",
|
| 335 |
+
"bytes": 484,
|
| 336 |
+
"expanded_bytes": 1942,
|
| 337 |
+
"native_scene_equal_to_reference_layout": true,
|
| 338 |
+
"game_editor_load_verified": false,
|
| 339 |
+
"dummy_lap_counts": [
|
| 340 |
+
1,
|
| 341 |
+
2,
|
| 342 |
+
3
|
| 343 |
+
],
|
| 344 |
+
"original_race_behavior_included": false
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"file": "tracks/Replica R04 Truck Maze.track",
|
| 348 |
+
"display_name": "Replica R04 Truck Maze",
|
| 349 |
+
"reference_label": "R04 Truck Maze",
|
| 350 |
+
"id": "54d93736-7aca-5bf6-9f04-6baddaa8f720",
|
| 351 |
+
"tile_count": 22,
|
| 352 |
+
"challenge_count": 3,
|
| 353 |
+
"challenge_source": "dummy_lap_challenges",
|
| 354 |
+
"original_campaign_unlock_stars": 0,
|
| 355 |
+
"sha256": "d7b89d64e118506e6cec259057886d9267ca4c6fab570e7ba0d6641e8f822f11",
|
| 356 |
+
"bytes": 546,
|
| 357 |
+
"expanded_bytes": 2712,
|
| 358 |
+
"native_scene_equal_to_reference_layout": true,
|
| 359 |
+
"game_editor_load_verified": false,
|
| 360 |
+
"dummy_lap_counts": [
|
| 361 |
+
1,
|
| 362 |
+
2,
|
| 363 |
+
3
|
| 364 |
+
],
|
| 365 |
+
"original_race_behavior_included": false
|
| 366 |
+
},
|
| 367 |
+
{
|
| 368 |
+
"file": "tracks/Replica R05 Endurance 500.track",
|
| 369 |
+
"display_name": "Replica R05 Endurance 500",
|
| 370 |
+
"reference_label": "R05 Endurance 500",
|
| 371 |
+
"id": "6310df17-ac5d-5c88-9dea-35a3e125f4fb",
|
| 372 |
+
"tile_count": 8,
|
| 373 |
+
"challenge_count": 3,
|
| 374 |
+
"challenge_source": "dummy_lap_challenges",
|
| 375 |
+
"original_campaign_unlock_stars": 0,
|
| 376 |
+
"sha256": "dde36ad5f627bce65d45a96d46a68497f8d446f6011c9df19ee51ce71375cba8",
|
| 377 |
+
"bytes": 421,
|
| 378 |
+
"expanded_bytes": 1323,
|
| 379 |
+
"native_scene_equal_to_reference_layout": true,
|
| 380 |
+
"game_editor_load_verified": false,
|
| 381 |
+
"dummy_lap_counts": [
|
| 382 |
+
1,
|
| 383 |
+
2,
|
| 384 |
+
3
|
| 385 |
+
],
|
| 386 |
+
"original_race_behavior_included": false
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"file": "tracks/Replica R06 Mix.track",
|
| 390 |
+
"display_name": "Replica R06 Mix",
|
| 391 |
+
"reference_label": "R06 Mix",
|
| 392 |
+
"id": "88f19bd6-6793-5afd-a6d5-b57e4e1dcc8b",
|
| 393 |
+
"tile_count": 16,
|
| 394 |
+
"challenge_count": 3,
|
| 395 |
+
"challenge_source": "dummy_lap_challenges",
|
| 396 |
+
"original_campaign_unlock_stars": 0,
|
| 397 |
+
"sha256": "9de8d912a59001ea13baa7f1b4f92884b8cddf91978f31e19f3237975713f739",
|
| 398 |
+
"bytes": 506,
|
| 399 |
+
"expanded_bytes": 2141,
|
| 400 |
+
"native_scene_equal_to_reference_layout": true,
|
| 401 |
+
"game_editor_load_verified": false,
|
| 402 |
+
"dummy_lap_counts": [
|
| 403 |
+
1,
|
| 404 |
+
2,
|
| 405 |
+
3
|
| 406 |
+
],
|
| 407 |
+
"original_race_behavior_included": false
|
| 408 |
+
},
|
| 409 |
+
{
|
| 410 |
+
"file": "tracks/Replica R07 Mirage Marina.track",
|
| 411 |
+
"display_name": "Replica R07 Mirage Marina",
|
| 412 |
+
"reference_label": "R07 Mirage Marina",
|
| 413 |
+
"id": "a7d250e1-1ad3-575c-aec4-abff2fb78ace",
|
| 414 |
+
"tile_count": 34,
|
| 415 |
+
"challenge_count": 3,
|
| 416 |
+
"challenge_source": "dummy_lap_challenges",
|
| 417 |
+
"original_campaign_unlock_stars": 0,
|
| 418 |
+
"sha256": "8c6764f3accb1a8372d910d57f4f681572dd40c590c4a3d03517379bb360fcd7",
|
| 419 |
+
"bytes": 669,
|
| 420 |
+
"expanded_bytes": 3912,
|
| 421 |
+
"native_scene_equal_to_reference_layout": true,
|
| 422 |
+
"game_editor_load_verified": false,
|
| 423 |
+
"dummy_lap_counts": [
|
| 424 |
+
1,
|
| 425 |
+
2,
|
| 426 |
+
3
|
| 427 |
+
],
|
| 428 |
+
"original_race_behavior_included": false
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"file": "tracks/Replica R08 Demolition Derby.track",
|
| 432 |
+
"display_name": "Replica R08 Demolition Derby",
|
| 433 |
+
"reference_label": "R08 Demolition Derby",
|
| 434 |
+
"id": "fbac2103-2234-5574-80b3-d94daf816f97",
|
| 435 |
+
"tile_count": 10,
|
| 436 |
+
"challenge_count": 3,
|
| 437 |
+
"challenge_source": "dummy_lap_challenges",
|
| 438 |
+
"original_campaign_unlock_stars": 0,
|
| 439 |
+
"sha256": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 440 |
+
"bytes": 447,
|
| 441 |
+
"expanded_bytes": 1518,
|
| 442 |
+
"native_scene_equal_to_reference_layout": true,
|
| 443 |
+
"game_editor_load_verified": false,
|
| 444 |
+
"dummy_lap_counts": [
|
| 445 |
+
1,
|
| 446 |
+
2,
|
| 447 |
+
3
|
| 448 |
+
],
|
| 449 |
+
"original_race_behavior_included": false
|
| 450 |
+
},
|
| 451 |
+
{
|
| 452 |
+
"file": "tracks/Replica R09 Eau Noir.track",
|
| 453 |
+
"display_name": "Replica R09 Eau Noir",
|
| 454 |
+
"reference_label": "R09 Eau Noir",
|
| 455 |
+
"id": "f97eca66-0455-5e8d-af0c-bc8fd3b11569",
|
| 456 |
+
"tile_count": 28,
|
| 457 |
+
"challenge_count": 3,
|
| 458 |
+
"challenge_source": "dummy_lap_challenges",
|
| 459 |
+
"original_campaign_unlock_stars": 0,
|
| 460 |
+
"sha256": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 461 |
+
"bytes": 609,
|
| 462 |
+
"expanded_bytes": 3302,
|
| 463 |
+
"native_scene_equal_to_reference_layout": true,
|
| 464 |
+
"game_editor_load_verified": false,
|
| 465 |
+
"dummy_lap_counts": [
|
| 466 |
+
1,
|
| 467 |
+
2,
|
| 468 |
+
3
|
| 469 |
+
],
|
| 470 |
+
"original_race_behavior_included": false
|
| 471 |
+
},
|
| 472 |
+
{
|
| 473 |
+
"file": "tracks/Replica The Champions Trial.track",
|
| 474 |
+
"display_name": "Replica The Champions Trial",
|
| 475 |
+
"reference_label": "The Champions Trial",
|
| 476 |
+
"id": "86d13552-32e0-583a-9e95-f8df9717c9da",
|
| 477 |
+
"tile_count": 76,
|
| 478 |
+
"challenge_count": 3,
|
| 479 |
+
"challenge_source": "dummy_lap_challenges",
|
| 480 |
+
"original_campaign_unlock_stars": 81,
|
| 481 |
+
"sha256": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 482 |
+
"bytes": 976,
|
| 483 |
+
"expanded_bytes": 8080,
|
| 484 |
+
"native_scene_equal_to_reference_layout": true,
|
| 485 |
+
"game_editor_load_verified": false,
|
| 486 |
+
"dummy_lap_counts": [
|
| 487 |
+
1,
|
| 488 |
+
2,
|
| 489 |
+
3
|
| 490 |
+
],
|
| 491 |
+
"original_race_behavior_included": false
|
| 492 |
+
}
|
| 493 |
+
]
|
| 494 |
+
}
|
builtin_tracks/tracks/Replica A01 Beginner.track
ADDED
|
Binary file (453 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A02 Sharp Turns.track
ADDED
|
Binary file (465 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A03 High Speed.track
ADDED
|
Binary file (528 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A04 Dirt.track
ADDED
|
Binary file (547 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A05 Two Terrains.track
ADDED
|
Binary file (567 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A06 Ice.track
ADDED
|
Binary file (508 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A07 Three Terrains.track
ADDED
|
Binary file (533 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A08 Long.track
ADDED
|
Binary file (683 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica A09 Sharpest.track
ADDED
|
Binary file (584 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B01 Oval.track
ADDED
|
Binary file (477 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B02 Snake.track
ADDED
|
Binary file (555 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B03 Slalom.track
ADDED
|
Binary file (530 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B04 Rally.track
ADDED
|
Binary file (648 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B05 Racetrack.track
ADDED
|
Binary file (627 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B06 Hard.track
ADDED
|
Binary file (674 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B07 Drift.track
ADDED
|
Binary file (570 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B08 Arctic Circle.track
ADDED
|
Binary file (709 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica B09 Checkered.track
ADDED
|
Binary file (810 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R01 Blitzring.track
ADDED
|
Binary file (518 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R02 Desert Rally.track
ADDED
|
Binary file (552 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R03 Glacier.track
ADDED
|
Binary file (484 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R04 Truck Maze.track
ADDED
|
Binary file (546 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R05 Endurance 500.track
ADDED
|
Binary file (421 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R06 Mix.track
ADDED
|
Binary file (506 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R07 Mirage Marina.track
ADDED
|
Binary file (669 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R08 Demolition Derby.track
ADDED
|
Binary file (447 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica R09 Eau Noir.track
ADDED
|
Binary file (609 Bytes). View file
|
|
|
builtin_tracks/tracks/Replica The Champions Trial.track
ADDED
|
Binary file (976 Bytes). View file
|
|
|
client.js
CHANGED
|
@@ -13,7 +13,10 @@ let batchReceipt = null;
|
|
| 13 |
// Display context affects quota guidance, never whether GPU can be selected.
|
| 14 |
const hostedStandalone = location.hostname.endsWith('.hf.space') && window.self === window.top;
|
| 15 |
const say = text => { $('status').textContent = text; };
|
|
|
|
|
|
|
| 16 |
function buttons() {
|
|
|
|
| 17 |
window.HFAuth?.setBusy(busy || !!job);
|
| 18 |
window.setTrainingBusy?.(busy || !!job);
|
| 19 |
window.setEditorBusy?.(busy || !!job);
|
|
@@ -118,7 +121,8 @@ $('run').onclick = async () => {
|
|
| 118 |
tick(); const progress=setInterval(tick,250);
|
| 119 |
busy=true; buttons(); say(window.getTrainingSettings?'Processing the training run…':'Processing the bounded test…');
|
| 120 |
try {
|
| 121 |
-
const
|
|
|
|
| 122 |
if(window.getTrainingSettings)body.settings=window.getTrainingSettings();
|
| 123 |
job=await submit(body);localResult=null;
|
| 124 |
clearInterval(progress);
|
|
@@ -128,6 +132,7 @@ $('run').onclick = async () => {
|
|
| 128 |
const metric=n=>typeof n==='number'?n.toFixed(3):'Not reported';
|
| 129 |
$('runSummary').textContent=r?[
|
| 130 |
'Backend: '+job.backend.toUpperCase(),
|
|
|
|
| 131 |
'Generations: '+r.generations_completed+' / '+r.generations_requested+' · Population: '+r.population,
|
| 132 |
'Server processing: '+metric(r.elapsed_seconds)+' s',
|
| 133 |
'Best score: '+metric(r.best_score)+' · Mean score: '+metric(r.mean_score),
|
|
@@ -177,7 +182,8 @@ if($('batch_start')){
|
|
| 177 |
try{
|
| 178 |
if(busy||job||!capabilitiesReady)throw Error('Finish the current job and connect first');
|
| 179 |
plan=window.getBatchPlan();
|
| 180 |
-
|
|
|
|
| 181 |
await encoded(original); // Reject missing/oversize inputs before dispatch.
|
| 182 |
const backend=$('backend').value;
|
| 183 |
busy=true;batchActive=true;batchStopRequested=false;batchReceipt=null;buttons();
|
|
@@ -203,7 +209,7 @@ if($('batch_start')){
|
|
| 203 |
line.textContent='Step '+step.step+' · '+step.slot+' · '+step.name+' · completed · '+step.report.generations_completed+' generations · server copy deleted';
|
| 204 |
$('batch_history').append(line);
|
| 205 |
}});
|
| 206 |
-
batchReceipt={version:1,state:result.state,plan,history,elapsed_seconds:(Date.now()-started)/1000};
|
| 207 |
$('batch_status').textContent=result.state.toUpperCase()+' · '+history.length+' / '+plan.runs.length+' runs. '+(localResult?'Last received candidate is available on Drive & view.':'No candidate received.');
|
| 208 |
$('runState').textContent='BATCH '+result.state.toUpperCase()+' — '+history.length+' / '+plan.runs.length+' runs; server copies deleted';
|
| 209 |
$('runState').style.color=result.state==='completed'?'#62dfb1':'#ffd073';
|
|
|
|
| 13 |
// Display context affects quota guidance, never whether GPU can be selected.
|
| 14 |
const hostedStandalone = location.hostname.endsWith('.hf.space') && window.self === window.top;
|
| 15 |
const say = text => { $('status').textContent = text; };
|
| 16 |
+
const trackLibrary=window.TrackLibrary?.mount({document,fetch,digest:sha});
|
| 17 |
+
const trackSource=()=>trackLibrary?trackLibrary.file():Promise.resolve($('track').files[0]);
|
| 18 |
function buttons() {
|
| 19 |
+
trackLibrary?.setBusy(busy || !!job);
|
| 20 |
window.HFAuth?.setBusy(busy || !!job);
|
| 21 |
window.setTrainingBusy?.(busy || !!job);
|
| 22 |
window.setEditorBusy?.(busy || !!job);
|
|
|
|
| 121 |
tick(); const progress=setInterval(tick,250);
|
| 122 |
busy=true; buttons(); say(window.getTrainingSettings?'Processing the training run…':'Processing the bounded test…');
|
| 123 |
try {
|
| 124 |
+
const trackInfo=trackLibrary?.info();
|
| 125 |
+
const body={track:await encoded(await trackSource()),network:await encoded(networkSource()),automatic:$('automatic').checked,backend:$('backend').value};
|
| 126 |
if(window.getTrainingSettings)body.settings=window.getTrainingSettings();
|
| 127 |
job=await submit(body);localResult=null;
|
| 128 |
clearInterval(progress);
|
|
|
|
| 132 |
const metric=n=>typeof n==='number'?n.toFixed(3):'Not reported';
|
| 133 |
$('runSummary').textContent=r?[
|
| 134 |
'Backend: '+job.backend.toUpperCase(),
|
| 135 |
+
'Track: '+(trackInfo?.source==='builtin'?trackInfo.display_name:'Custom upload'),
|
| 136 |
'Generations: '+r.generations_completed+' / '+r.generations_requested+' · Population: '+r.population,
|
| 137 |
'Server processing: '+metric(r.elapsed_seconds)+' s',
|
| 138 |
'Best score: '+metric(r.best_score)+' · Mean score: '+metric(r.mean_score),
|
|
|
|
| 182 |
try{
|
| 183 |
if(busy||job||!capabilitiesReady)throw Error('Finish the current job and connect first');
|
| 184 |
plan=window.getBatchPlan();
|
| 185 |
+
busy=true;buttons(); // Freeze both selectors before an asynchronous track fetch.
|
| 186 |
+
const track=await encoded(await trackSource()),original=networkSource();
|
| 187 |
await encoded(original); // Reject missing/oversize inputs before dispatch.
|
| 188 |
const backend=$('backend').value;
|
| 189 |
busy=true;batchActive=true;batchStopRequested=false;batchReceipt=null;buttons();
|
|
|
|
| 209 |
line.textContent='Step '+step.step+' · '+step.slot+' · '+step.name+' · completed · '+step.report.generations_completed+' generations · server copy deleted';
|
| 210 |
$('batch_history').append(line);
|
| 211 |
}});
|
| 212 |
+
batchReceipt={version:1,state:result.state,plan,track:trackLibrary?.info()??{source:'upload'},history,elapsed_seconds:(Date.now()-started)/1000};
|
| 213 |
$('batch_status').textContent=result.state.toUpperCase()+' · '+history.length+' / '+plan.runs.length+' runs. '+(localResult?'Last received candidate is available on Drive & view.':'No candidate received.');
|
| 214 |
$('runState').textContent='BATCH '+result.state.toUpperCase()+' — '+history.length+' / '+plan.runs.length+' runs; server copies deleted';
|
| 215 |
$('runState').style.color=result.state==='completed'?'#62dfb1':'#ffd073';
|
index.html
CHANGED
|
@@ -7,6 +7,9 @@
|
|
| 7 |
<p><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>
|
| 8 |
<button id="retry" type="button">Retry connection</button>
|
| 9 |
<p><button id="hfSignIn" type="button" disabled>Sign in with Hugging Face</button> <button id="hfSignOut" type="button" disabled>Sign out of this app</button> <button id="hfVerify" type="button" disabled>Verify HF identity — no GPU</button></p><p id="hfIdentity" role="status" class="hint">CPU needs no sign-in. Checking optional HF sign-in…</p>
|
|
|
|
|
|
|
|
|
|
| 10 |
<p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
|
| 11 |
<p><label>Formula network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
|
| 12 |
<p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p><label><input id="automatic" type="checkbox" checked> Automatically delete server-side job data after receiving the result</label></p>
|
|
@@ -18,7 +21,7 @@
|
|
| 18 |
<pre id="runSummary" style="white-space:pre-wrap;line-height:1.7" aria-live="polite"></pre>
|
| 19 |
<p id="deadline"></p><p id="status" role="status">Ready. Inputs remain on this device until you run the test.</p>
|
| 20 |
<details><summary>Effective training settings</summary><pre id="effectiveSettings"></pre></details><details><summary>Generation results</summary><pre id="generationHistory"></pre></details><details><summary>Star challenges — not evaluated</summary><p>The current runner has star-challenge reporting. Its evaluator and required statistics have not been ported to HF; no star result is inferred from a completed test.</p></details><h2>Selected track & terrain</h2><div class="map" role="img" aria-label="Track map placeholder"><strong>Track map</strong><p>Renderer not connected yet.</p></div></section></div>
|
| 21 |
-
</div><section id="training" class="pane" hidden><div class="card"><h2>Training settings</h2><p class="hint">Choose the track on Drive & view. Choose the training settings and reward mix here, then start the run on Drive & view. Recipes and batch sequences are saved in this browser.</p><div id="training_controls"><label for="training_ticks">Simulated ticks per generation</label><input id="training_ticks" type="number" min="1" max="18000" value="60"><small>60 ticks = one simulated second. Current preview limit: population × generations × ticks ≤ 4,000,000; execution timeout 25 seconds.</small>
|
| 22 |
<div class="row"><div><label for="population">Population</label><input id="population" type="number" min="1" max="128" value="8" disabled><small>Population limits will follow the selected compute allocation.</small></div><div><label for="generations">Generations</label><input id="generations" type="number" min="1" max="1000" value="30" disabled><small>1–1,000; try 20–50 before review.</small></div></div>
|
| 23 |
<label id="mutation_label" for="mutation">Mutation rate</label><input id="mutation" type="number" min="0" max="4.2" step="0.01" value="0.1" disabled><small>Mutation settings are passed to the upstream simulator.</small>
|
| 24 |
|
|
@@ -288,6 +291,85 @@
|
|
| 288 |
message('Batch '+batch.slot+' loaded. Loading a batch does not start it.');
|
| 289 |
});
|
| 290 |
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 291 |
</script><script src="/client.js"></script><script src="/hf-auth.js"></script><script>'use strict';
|
| 292 |
// Navigation only. Editor and training/storage adapters are separate layers.
|
| 293 |
document.querySelectorAll('[data-tab]').forEach(button=>button.addEventListener('click',()=>{
|
|
|
|
| 7 |
<p><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>
|
| 8 |
<button id="retry" type="button">Retry connection</button>
|
| 9 |
<p><button id="hfSignIn" type="button" disabled>Sign in with Hugging Face</button> <button id="hfSignOut" type="button" disabled>Sign out of this app</button> <button id="hfVerify" type="button" disabled>Verify HF identity — no GPU</button></p><p id="hfIdentity" role="status" class="hint">CPU needs no sign-in. Checking optional HF sign-in…</p>
|
| 10 |
+
<p><label for="trackPresetDrive">Track selection</label><select id="trackPresetDrive" data-track-library disabled><option value="">Upload a custom track</option></select></p>
|
| 11 |
+
<p data-track-status role="status" class="hint">Loading built-in replica tracks…</p>
|
| 12 |
+
<p class="hint">Built-in replicas are reconstructed editor-format layouts, not editor-authored or official packaged files. Star conditions are not evaluated.</p>
|
| 13 |
<p><label>Track (.track) <input id="track" type="file" accept=".track"></label></p>
|
| 14 |
<p><label>Formula network (.evolution) <input id="network" type="file" accept=".evolution"></label></p>
|
| 15 |
<p id="networkChoice" role="status">Choose an uploaded file or use a network from the browser editor.</p><p><label><input id="automatic" type="checkbox" checked> Automatically delete server-side job data after receiving the result</label></p>
|
|
|
|
| 21 |
<pre id="runSummary" style="white-space:pre-wrap;line-height:1.7" aria-live="polite"></pre>
|
| 22 |
<p id="deadline"></p><p id="status" role="status">Ready. Inputs remain on this device until you run the test.</p>
|
| 23 |
<details><summary>Effective training settings</summary><pre id="effectiveSettings"></pre></details><details><summary>Generation results</summary><pre id="generationHistory"></pre></details><details><summary>Star challenges — not evaluated</summary><p>The current runner has star-challenge reporting. Its evaluator and required statistics have not been ported to HF; no star result is inferred from a completed test.</p></details><h2>Selected track & terrain</h2><div class="map" role="img" aria-label="Track map placeholder"><strong>Track map</strong><p>Renderer not connected yet.</p></div></section></div>
|
| 24 |
+
</div><section id="training" class="pane" hidden><div class="card"><h2>Training settings</h2><p class="hint">Choose the track on Drive & view. Choose the training settings and reward mix here, then start the run on Drive & view. Recipes and batch sequences are saved in this browser.</p><p><label for="trackPresetTraining">Training track</label><select id="trackPresetTraining" data-track-library disabled><option value="">Upload a custom track</option></select></p><p data-track-status role="status" class="hint">Loading built-in replica tracks…</p><div id="training_controls"><label for="training_ticks">Simulated ticks per generation</label><input id="training_ticks" type="number" min="1" max="18000" value="60"><small>60 ticks = one simulated second. Current preview limit: population × generations × ticks ≤ 4,000,000; execution timeout 25 seconds.</small>
|
| 25 |
<div class="row"><div><label for="population">Population</label><input id="population" type="number" min="1" max="128" value="8" disabled><small>Population limits will follow the selected compute allocation.</small></div><div><label for="generations">Generations</label><input id="generations" type="number" min="1" max="1000" value="30" disabled><small>1–1,000; try 20–50 before review.</small></div></div>
|
| 26 |
<label id="mutation_label" for="mutation">Mutation rate</label><input id="mutation" type="number" min="0" max="4.2" step="0.01" value="0.1" disabled><small>Mutation settings are passed to the upstream simulator.</small>
|
| 27 |
|
|
|
|
| 291 |
message('Batch '+batch.slot+' loaded. Loading a batch does not start it.');
|
| 292 |
});
|
| 293 |
})();
|
| 294 |
+
</script><script>/* Read-only public reference library. No cookies or browser-persistent storage. */
|
| 295 |
+
(function(root,factory){
|
| 296 |
+
if(typeof module==='object'&&module.exports)module.exports=factory();
|
| 297 |
+
else root.TrackLibrary=factory();
|
| 298 |
+
})(typeof window==='undefined'?this:window,function(){
|
| 299 |
+
function create({fetch,digest,upload}){
|
| 300 |
+
let entries=[],selected='',cached=null;
|
| 301 |
+
return {
|
| 302 |
+
async load(){
|
| 303 |
+
const response=await fetch('/api/tracks',{cache:'no-store',credentials:'same-origin'});
|
| 304 |
+
if(!response.ok)throw Error('Built-in track catalog unavailable');
|
| 305 |
+
const catalog=await response.json();
|
| 306 |
+
if(!Array.isArray(catalog.tracks)||catalog.tracks.length>128)throw Error('Invalid track catalog');
|
| 307 |
+
const ids=new Set();
|
| 308 |
+
for(const entry of catalog.tracks){
|
| 309 |
+
if(!/^[a-z0-9-]{1,80}$/.test(entry.id)||ids.has(entry.id)||
|
| 310 |
+
typeof entry.display_name!=='string'||!entry.display_name.length||entry.display_name.length>100||
|
| 311 |
+
!Number.isInteger(entry.bytes)||entry.bytes<1||entry.bytes>1048576||
|
| 312 |
+
!/^[a-f0-9]{64}$/.test(entry.sha256))throw Error('Invalid track catalog');
|
| 313 |
+
ids.add(entry.id);
|
| 314 |
+
}
|
| 315 |
+
entries=catalog.tracks.map(entry=>({...entry}));
|
| 316 |
+
return this.entries();
|
| 317 |
+
},
|
| 318 |
+
entries:()=>entries.map(entry=>({...entry})),
|
| 319 |
+
selected:()=>selected,
|
| 320 |
+
select(id){
|
| 321 |
+
if(id&&!entries.some(entry=>entry.id===id))throw Error('Unknown built-in track');
|
| 322 |
+
if(id!==selected)cached=null;
|
| 323 |
+
selected=id;
|
| 324 |
+
},
|
| 325 |
+
info(){const entry=entries.find(entry=>entry.id===selected);return entry?{source:'builtin',...entry}:{source:'upload'};},
|
| 326 |
+
async file(){
|
| 327 |
+
if(!selected)return upload();
|
| 328 |
+
const entry=entries.find(entry=>entry.id===selected);
|
| 329 |
+
if(cached?.id===selected)return cached.blob;
|
| 330 |
+
const response=await fetch('/api/tracks/'+encodeURIComponent(selected)+'/file',
|
| 331 |
+
{cache:'no-store',credentials:'same-origin'});
|
| 332 |
+
if(!response.ok)throw Error('Built-in track unavailable; retry or choose an upload');
|
| 333 |
+
const bytes=await response.arrayBuffer();
|
| 334 |
+
if(bytes.byteLength!==entry.bytes||await digest(bytes)!==entry.sha256)
|
| 335 |
+
throw Error('Built-in track validation failed');
|
| 336 |
+
const blob=new Blob([bytes],{type:'application/octet-stream'});
|
| 337 |
+
cached={id:entry.id,blob};return blob;
|
| 338 |
+
}
|
| 339 |
+
};
|
| 340 |
+
}
|
| 341 |
+
function mount({document,fetch,digest}){
|
| 342 |
+
const selects=Array.from(document.querySelectorAll('[data-track-library]'));
|
| 343 |
+
const statuses=Array.from(document.querySelectorAll('[data-track-status]'));
|
| 344 |
+
const input=document.getElementById('track');
|
| 345 |
+
const picker=create({fetch,digest,upload:()=>input.files[0]});
|
| 346 |
+
let ready=false,busy=false;
|
| 347 |
+
function render(message){
|
| 348 |
+
for(const select of selects){select.value=picker.selected();select.disabled=busy||!ready;}
|
| 349 |
+
const info=picker.info();
|
| 350 |
+
for(const status of statuses)status.textContent=message??(info.source==='builtin'?
|
| 351 |
+
info.display_name+' selected. It remains selected after a run.':
|
| 352 |
+
'Upload mode selected. Built-in replicas can be selected instead.');
|
| 353 |
+
}
|
| 354 |
+
for(const select of selects)select.addEventListener('change',()=>{
|
| 355 |
+
picker.select(select.value);if(select.value)input.value='';render();
|
| 356 |
+
});
|
| 357 |
+
input.addEventListener('change',()=>{picker.select('');render();});
|
| 358 |
+
picker.setBusy=value=>{busy=value;render();};
|
| 359 |
+
picker.load().then(()=>{
|
| 360 |
+
for(const select of selects){
|
| 361 |
+
for(const entry of picker.entries()){
|
| 362 |
+
const option=document.createElement('option');option.value=entry.id;
|
| 363 |
+
option.textContent=entry.display_name;select.append(option);
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
ready=picker.entries().length>0;
|
| 367 |
+
render(ready?undefined:'No built-in tracks in this installation. Custom uploads still work.');
|
| 368 |
+
}).catch(()=>render('Built-in catalog unavailable. Custom uploads still work.'));
|
| 369 |
+
return picker;
|
| 370 |
+
}
|
| 371 |
+
return {create,mount};
|
| 372 |
+
});
|
| 373 |
</script><script src="/client.js"></script><script src="/hf-auth.js"></script><script>'use strict';
|
| 374 |
// Navigation only. Editor and training/storage adapters are separate layers.
|
| 375 |
document.querySelectorAll('[data-tab]').forEach(button=>button.addEventListener('click',()=>{
|
server.py
CHANGED
|
@@ -10,12 +10,25 @@ from delivery import create_api, CapacityExceeded
|
|
| 10 |
from worker import run_reported
|
| 11 |
from training_config import validate_config
|
| 12 |
from hf_identity import oauth_config
|
|
|
|
| 13 |
|
| 14 |
ROOT=Path(__file__).resolve().parent
|
| 15 |
|
| 16 |
-
def create_app(worker=run_reported,store=None,gpu_worker=None):
|
| 17 |
app=create_api(store)
|
| 18 |
admission=threading.BoundedSemaphore(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
@app.get('/api/auth/config')
|
| 20 |
def auth_config():
|
| 21 |
return JSONResponse(oauth_config(),headers={'Cache-Control':'no-store'})
|
|
|
|
| 10 |
from worker import run_reported
|
| 11 |
from training_config import validate_config
|
| 12 |
from hf_identity import oauth_config
|
| 13 |
+
from builtin_tracks import TrackLibrary
|
| 14 |
|
| 15 |
ROOT=Path(__file__).resolve().parent
|
| 16 |
|
| 17 |
+
def create_app(worker=run_reported,store=None,gpu_worker=None,track_library=None):
|
| 18 |
app=create_api(store)
|
| 19 |
admission=threading.BoundedSemaphore(1)
|
| 20 |
+
library=track_library if track_library is not None else TrackLibrary(ROOT/'builtin_tracks')
|
| 21 |
+
@app.get('/api/tracks')
|
| 22 |
+
def track_catalog():
|
| 23 |
+
return JSONResponse(library.catalog(),headers={'Cache-Control':'no-store'})
|
| 24 |
+
@app.get('/api/tracks/{identifier}/file')
|
| 25 |
+
def reference_track(identifier:str):
|
| 26 |
+
try:payload=library.read(identifier)
|
| 27 |
+
except KeyError:raise HTTPException(404,'Built-in track not found') from None
|
| 28 |
+
except (ValueError,OSError):raise HTTPException(503,'Built-in track validation failed') from None
|
| 29 |
+
return Response(payload,media_type='application/octet-stream',headers={'Cache-Control':'no-store'})
|
| 30 |
+
@app.get('/track-library.js')
|
| 31 |
+
def track_script():return FileResponse(ROOT/'track-library.js',media_type='text/javascript')
|
| 32 |
@app.get('/api/auth/config')
|
| 33 |
def auth_config():
|
| 34 |
return JSONResponse(oauth_config(),headers={'Cache-Control':'no-store'})
|
track-library.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Read-only public reference library. No cookies or browser-persistent storage. */
|
| 2 |
+
(function(root,factory){
|
| 3 |
+
if(typeof module==='object'&&module.exports)module.exports=factory();
|
| 4 |
+
else root.TrackLibrary=factory();
|
| 5 |
+
})(typeof window==='undefined'?this:window,function(){
|
| 6 |
+
function create({fetch,digest,upload}){
|
| 7 |
+
let entries=[],selected='',cached=null;
|
| 8 |
+
return {
|
| 9 |
+
async load(){
|
| 10 |
+
const response=await fetch('/api/tracks',{cache:'no-store',credentials:'same-origin'});
|
| 11 |
+
if(!response.ok)throw Error('Built-in track catalog unavailable');
|
| 12 |
+
const catalog=await response.json();
|
| 13 |
+
if(!Array.isArray(catalog.tracks)||catalog.tracks.length>128)throw Error('Invalid track catalog');
|
| 14 |
+
const ids=new Set();
|
| 15 |
+
for(const entry of catalog.tracks){
|
| 16 |
+
if(!/^[a-z0-9-]{1,80}$/.test(entry.id)||ids.has(entry.id)||
|
| 17 |
+
typeof entry.display_name!=='string'||!entry.display_name.length||entry.display_name.length>100||
|
| 18 |
+
!Number.isInteger(entry.bytes)||entry.bytes<1||entry.bytes>1048576||
|
| 19 |
+
!/^[a-f0-9]{64}$/.test(entry.sha256))throw Error('Invalid track catalog');
|
| 20 |
+
ids.add(entry.id);
|
| 21 |
+
}
|
| 22 |
+
entries=catalog.tracks.map(entry=>({...entry}));
|
| 23 |
+
return this.entries();
|
| 24 |
+
},
|
| 25 |
+
entries:()=>entries.map(entry=>({...entry})),
|
| 26 |
+
selected:()=>selected,
|
| 27 |
+
select(id){
|
| 28 |
+
if(id&&!entries.some(entry=>entry.id===id))throw Error('Unknown built-in track');
|
| 29 |
+
if(id!==selected)cached=null;
|
| 30 |
+
selected=id;
|
| 31 |
+
},
|
| 32 |
+
info(){const entry=entries.find(entry=>entry.id===selected);return entry?{source:'builtin',...entry}:{source:'upload'};},
|
| 33 |
+
async file(){
|
| 34 |
+
if(!selected)return upload();
|
| 35 |
+
const entry=entries.find(entry=>entry.id===selected);
|
| 36 |
+
if(cached?.id===selected)return cached.blob;
|
| 37 |
+
const response=await fetch('/api/tracks/'+encodeURIComponent(selected)+'/file',
|
| 38 |
+
{cache:'no-store',credentials:'same-origin'});
|
| 39 |
+
if(!response.ok)throw Error('Built-in track unavailable; retry or choose an upload');
|
| 40 |
+
const bytes=await response.arrayBuffer();
|
| 41 |
+
if(bytes.byteLength!==entry.bytes||await digest(bytes)!==entry.sha256)
|
| 42 |
+
throw Error('Built-in track validation failed');
|
| 43 |
+
const blob=new Blob([bytes],{type:'application/octet-stream'});
|
| 44 |
+
cached={id:entry.id,blob};return blob;
|
| 45 |
+
}
|
| 46 |
+
};
|
| 47 |
+
}
|
| 48 |
+
function mount({document,fetch,digest}){
|
| 49 |
+
const selects=Array.from(document.querySelectorAll('[data-track-library]'));
|
| 50 |
+
const statuses=Array.from(document.querySelectorAll('[data-track-status]'));
|
| 51 |
+
const input=document.getElementById('track');
|
| 52 |
+
const picker=create({fetch,digest,upload:()=>input.files[0]});
|
| 53 |
+
let ready=false,busy=false;
|
| 54 |
+
function render(message){
|
| 55 |
+
for(const select of selects){select.value=picker.selected();select.disabled=busy||!ready;}
|
| 56 |
+
const info=picker.info();
|
| 57 |
+
for(const status of statuses)status.textContent=message??(info.source==='builtin'?
|
| 58 |
+
info.display_name+' selected. It remains selected after a run.':
|
| 59 |
+
'Upload mode selected. Built-in replicas can be selected instead.');
|
| 60 |
+
}
|
| 61 |
+
for(const select of selects)select.addEventListener('change',()=>{
|
| 62 |
+
picker.select(select.value);if(select.value)input.value='';render();
|
| 63 |
+
});
|
| 64 |
+
input.addEventListener('change',()=>{picker.select('');render();});
|
| 65 |
+
picker.setBusy=value=>{busy=value;render();};
|
| 66 |
+
picker.load().then(()=>{
|
| 67 |
+
for(const select of selects){
|
| 68 |
+
for(const entry of picker.entries()){
|
| 69 |
+
const option=document.createElement('option');option.value=entry.id;
|
| 70 |
+
option.textContent=entry.display_name;select.append(option);
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
ready=picker.entries().length>0;
|
| 74 |
+
render(ready?undefined:'No built-in tracks in this installation. Custom uploads still work.');
|
| 75 |
+
}).catch(()=>render('Built-in catalog unavailable. Custom uploads still work.'));
|
| 76 |
+
return picker;
|
| 77 |
+
}
|
| 78 |
+
return {create,mount};
|
| 79 |
+
});
|