Spaces:
Running on Zero
Running on Zero
Prepare public beta: in-page confirmations, feedback and safe GPU errors
Browse filesKeep existing Space access settings. Add recipe-import recovery, capability gates, GitHub issue drafts and bounded CUDA reference instructions; preserve simulator binaries.
- BETA_TESTING.md +61 -94
- CUDA_REFERENCE.md +67 -0
- DATA_POLICY.md +2 -2
- FEEDBACK.md +4 -3
- FRONTEND_SOURCE.json +3 -3
- README.md +3 -1
- RELEASE_MANIFEST.json +11 -10
- TRACK_LIBRARY.md +2 -1
- app.py +11 -2
- client.js +17 -5
- hf-auth.js +1 -1
- index.html +36 -10
BETA_TESTING.md
CHANGED
|
@@ -1,94 +1,61 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
##
|
| 8 |
-
|
| 9 |
-
The Space
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
from a successful artifact lifecycle test. A bucket and broad network support
|
| 63 |
-
remain separate work.
|
| 64 |
-
|
| 65 |
-
## Reporting through GitHub
|
| 66 |
-
|
| 67 |
-
Prepare read access plus issue filing, without write/merge/deployment privileges.
|
| 68 |
-
The local issue-form draft is under `.github/ISSUE_TEMPLATE/runner_beta.yml`.
|
| 69 |
-
It is not live until reviewed and committed/pushed to the intended repository.
|
| 70 |
-
Repository invitations and collaborator permissions require named recipients;
|
| 71 |
-
no invitations have been sent by this work.
|
| 72 |
-
|
| 73 |
-
Reports should include browser/version, OS, build ID, CPU/GPU, reproduction steps,
|
| 74 |
-
expected/actual behavior and a redacted screenshot or receipt. Do not attach a
|
| 75 |
-
private trained network, a proprietary game-extracted track, tokens, job access
|
| 76 |
-
keys, or full unrelated logs to an ordinary bug report. Use public/generated
|
| 77 |
-
fixtures or describe the network shape and sensor/output contract.
|
| 78 |
-
|
| 79 |
-
## Local 2026-10-13 candidate (not deployed)
|
| 80 |
-
|
| 81 |
-
Content-addressed build IDs now appear in capabilities and exported run/batch receipts;
|
| 82 |
-
reports include upstream simulator revision and packaged binary SHA-256 values.
|
| 83 |
-
A single run has its own receipt export. `/feedback` supplies a private-feedback
|
| 84 |
-
template; no public issue destination or invitation is activated.
|
| 85 |
-
|
| 86 |
-
The native train-scratch adapter requires positive mutation even when continuing an
|
| 87 |
-
uploaded network. The form and server now reject zero before native dispatch.
|
| 88 |
-
Any GPU dispatch error attempts to discard its pending ticket; a missing ticket
|
| 89 |
-
is not evidence that an already dispatched run stopped.
|
| 90 |
-
|
| 91 |
-
This candidate requires an explicitly approved deployment followed by hosted
|
| 92 |
-
CPU/GPU and real-account checks before tester invitations. Local checks and
|
| 93 |
-
training experiments against the previous live build are recorded outside this
|
| 94 |
-
package in the sibling sprint receipt. They do not qualify this candidate as deployed.
|
|
|
|
| 1 |
+
# Public launch preflight
|
| 2 |
+
|
| 3 |
+
This document defines the hosted qualification checks for the release package.
|
| 4 |
+
Deployment status and build-specific acceptance belong in the release receipt;
|
| 5 |
+
results from one build do not qualify another build.
|
| 6 |
+
|
| 7 |
+
## Intended launch topology
|
| 8 |
+
|
| 9 |
+
- The GPU Space app is publicly reachable at
|
| 10 |
+
https://tiga-rce-ald-tao-gpu.hf.space/.
|
| 11 |
+
- The GPU Space source repository remains restricted.
|
| 12 |
+
- The standalone CPU Space remains private. The public GPU app also offers an
|
| 13 |
+
anonymous CPU route, which does not acquire a GPU lease.
|
| 14 |
+
|
| 15 |
+
App access and source-repository access are separate. Do not send users to the
|
| 16 |
+
restricted source repository as the app entry point.
|
| 17 |
+
|
| 18 |
+
## Required qualification for each deployed build
|
| 19 |
+
|
| 20 |
+
1. Freeze the allow-listed package and verify its file manifest after source
|
| 21 |
+
and documentation changes.
|
| 22 |
+
2. Deploy the package in the intended topology. Record the exact Space commit,
|
| 23 |
+
visibility, runtime stage, and build ID in the release receipt.
|
| 24 |
+
3. On the deployed build, verify CPU upload → run → download → receipt
|
| 25 |
+
acknowledgement → server-side 404 using disposable generated files.
|
| 26 |
+
4. Check included HF allowance before one bounded GPU fixture run. Verify the
|
| 27 |
+
CUDA report, candidate hash, download, and deletion; do not use paid overage.
|
| 28 |
+
A quota rejection must show CPU/account guidance and report whether the
|
| 29 |
+
pending ticket was discarded or already consumed.
|
| 30 |
+
5. Verify optional HF sign-in and account attribution separately from an
|
| 31 |
+
anonymous GPU run. Do not ask users to paste personal access tokens.
|
| 32 |
+
6. Exercise result expiry, opt-in repeat download, manual deletion, malformed
|
| 33 |
+
inputs, native failure, and temporary-file cleanup on the deployed build.
|
| 34 |
+
7. Confirm recipe and batch behavior in supported browsers. A successful
|
| 35 |
+
artifact lifecycle check does not imply training quality or game parity.
|
| 36 |
+
|
| 37 |
+
## Supported runner contract
|
| 38 |
+
|
| 39 |
+
The worker accepts Formula steering/acceleration networks with two outputs,
|
| 40 |
+
two to four layers, at most 16 nodes per layer, speed and raycast sensors, and
|
| 41 |
+
bounded execution settings. Unsupported network shapes or sensors are not
|
| 42 |
+
accepted for training. The track preview shows tile layout and terrain, not
|
| 43 |
+
collision geometry. Star challenges are not evaluated.
|
| 44 |
+
|
| 45 |
+
## CUDA reference check
|
| 46 |
+
|
| 47 |
+
Use the deterministic generated network and bundled Replica B01 Oval track
|
| 48 |
+
described in `CUDA_REFERENCE.md`. Keep input hashes, candidate output hash,
|
| 49 |
+
settings, build ID, binary hashes, and deletion receipts together. The
|
| 50 |
+
single fixture cannot establish general CUDA/CPU equivalence, original-game
|
| 51 |
+
parity, or training quality.
|
| 52 |
+
|
| 53 |
+
## Feedback
|
| 54 |
+
|
| 55 |
+
`/feedback` serves a template only; it does not submit a report. The configured
|
| 56 |
+
public destination is the [driving_sim_rs issue tracker](https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new).
|
| 57 |
+
Reports should identify the app URL and build ID, browser and version, operating
|
| 58 |
+
system, CPU/GPU choice, reproduction steps, expected and observed behavior, and
|
| 59 |
+
a redacted receipt or screenshot. Do not attach tokens, job access keys, private
|
| 60 |
+
networks, proprietary tracks, or unrelated logs. Inspect receipts before
|
| 61 |
+
sharing; batch receipts also include recipe and batch names.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CUDA_REFERENCE.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Bounded CUDA reference check
|
| 2 |
+
|
| 3 |
+
This protocol checks that the hosted CUDA path can accept a known small input,
|
| 4 |
+
complete one bounded Formula training run, return a validated artifact, and
|
| 5 |
+
delete the server copy after verified download. It is not a test of broad game
|
| 6 |
+
parity, training quality, or general CPU/GPU equivalence.
|
| 7 |
+
|
| 8 |
+
## Public-package fixture
|
| 9 |
+
|
| 10 |
+
- Track: `builtin_tracks/tracks/Replica B01 Oval.track`, catalog ID
|
| 11 |
+
`787f73f5-3b8c-5d95-b0e3-0016ed076970`, SHA-256
|
| 12 |
+
`0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158`.
|
| 13 |
+
- Network: deterministic, generated Formula network, shape `[6,4,2]`; one
|
| 14 |
+
speed sensor and five raycasts at `-60,-30,0,30,60` degrees with length 800;
|
| 15 |
+
outputs `[0,1]`; for zero-based indices, first-layer weight `W[i][j]` is
|
| 16 |
+
`(i+1)*(j+1)/100`, second-layer `W[i][j]` is `(i+1)*(j-0.5)/10`, and every
|
| 17 |
+
bias is zero. Serialize the JSON with sorted keys and compact separators.
|
| 18 |
+
- Generated network bytes: 554; SHA-256
|
| 19 |
+
`d9851cb1eee40dee78fb8c4492caeac8f130b5543f6d4551bb2175c13c579c3b`.
|
| 20 |
+
|
| 21 |
+
The following standard-library Python snippet is the complete network fixture
|
| 22 |
+
generator. It prints the exact bytes and digest; `Name` is intentionally absent
|
| 23 |
+
because the worker does not require it.
|
| 24 |
+
|
| 25 |
+
```python
|
| 26 |
+
import hashlib
|
| 27 |
+
import json
|
| 28 |
+
|
| 29 |
+
def generated_network():
|
| 30 |
+
shape = [6, 4, 2]
|
| 31 |
+
first = [[(i + 1) * (j + 1) / 100 for j in range(4)] for i in range(6)]
|
| 32 |
+
second = [[(i + 1) * (j - 0.5) / 10 for j in range(2)] for i in range(4)]
|
| 33 |
+
value = {
|
| 34 |
+
"Type": 0,
|
| 35 |
+
"Outputs": [0, 1],
|
| 36 |
+
"Sensors": [
|
| 37 |
+
{"$type": "speed"},
|
| 38 |
+
*[
|
| 39 |
+
{"$type": "raycast", "Degrees": angle, "Length": 800}
|
| 40 |
+
for angle in (-60, -30, 0, 30, 60)
|
| 41 |
+
],
|
| 42 |
+
],
|
| 43 |
+
"NeuralNetwork": {
|
| 44 |
+
"Shape": shape,
|
| 45 |
+
"Weights": [first, second],
|
| 46 |
+
"Biases": [[0.0] * 4, [0.0, 0.0]],
|
| 47 |
+
},
|
| 48 |
+
}
|
| 49 |
+
return json.dumps(value, sort_keys=True, separators=(",", ":")).encode()
|
| 50 |
+
|
| 51 |
+
network = generated_network()
|
| 52 |
+
print(len(network), hashlib.sha256(network).hexdigest())
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
Pair these network bytes with the unchanged `Replica B01 Oval.track` file from
|
| 56 |
+
the package; do not rewrite the compressed track file.
|
| 57 |
+
|
| 58 |
+
- Bounded run settings: population 1, generation 1, 120 ticks, mutation 0.01,
|
| 59 |
+
seed 42, one worker, default total-score reward. These are a smoke fixture,
|
| 60 |
+
not a quality recommendation.
|
| 61 |
+
|
| 62 |
+
For a live CUDA qualification, first verify the target build ID and included HF
|
| 63 |
+
allowance. Run the fixture once through CPU and once through GPU on the same
|
| 64 |
+
build when CUDA quota permits. Record both reports, output SHA-256 values, binary
|
| 65 |
+
hashes, candidate validation, and deletion receipts. A mismatch is a finding to
|
| 66 |
+
investigate; do not widen the claim from this one track/network/settings tuple.
|
| 67 |
+
Do not spend paid overage. No live GPU job was run to prepare this protocol.
|
DATA_POLICY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
# Data handling & deletion policy —
|
| 2 |
|
| 3 |
-
Operator: TiGa (seeker-cyber-maker).
|
| 4 |
|
| 5 |
Files are processed only for the requested job, not collected for our own
|
| 6 |
training, analytics or public examples. Inputs remain in the browser until Run.
|
|
|
|
| 1 |
+
# Data handling & deletion policy — public-release candidate
|
| 2 |
|
| 3 |
+
Operator: TiGa (seeker-cyber-maker). Candidate version: 2026-10-13. This package is not a receipt that a hosted deployment or publication has occurred.
|
| 4 |
|
| 5 |
Files are processed only for the requested job, not collected for our own
|
| 6 |
training, analytics or public examples. Inputs remain in the browser until Run.
|
FEEDBACK.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
| 1 |
-
#
|
| 2 |
|
| 3 |
This form is a local template. It does not submit a message or upload files.
|
| 4 |
-
|
| 5 |
-
|
|
|
|
| 6 |
|
| 7 |
- App URL:
|
| 8 |
- Build ID (from an exported run or batch receipt):
|
|
|
|
| 1 |
+
# Feedback report template
|
| 2 |
|
| 3 |
This form is a local template. It does not submit a message or upload files.
|
| 4 |
+
Use the public issue form at https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new
|
| 5 |
+
to report a problem. Review every attachment before posting. The issue tracker is
|
| 6 |
+
for product reports; do not include confidential material.
|
| 7 |
|
| 8 |
- App URL:
|
| 9 |
- Build ID (from an exported run or batch receipt):
|
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": "
|
| 5 |
"scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
|
| 6 |
-
"status": "
|
| 7 |
"track_atlas_sha256": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
|
| 8 |
-
"client_sha256": "
|
| 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": "aeb602565bf2da9d40cb6c3aae0b6e713b89e79a81557fed3e7f3dd8d16f195c",
|
| 5 |
"scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
|
| 6 |
+
"status": "Public beta release candidate; local verification pending hosted qualification",
|
| 7 |
"track_atlas_sha256": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
|
| 8 |
+
"client_sha256": "b6c2e0439bc1e4cf55c5e751e497e842e1e911b229f7480d7b1e04dea246536f",
|
| 9 |
"track_map_sha256": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"
|
| 10 |
}
|
README.md
CHANGED
|
@@ -8,8 +8,10 @@ hf_oauth: true
|
|
| 8 |
hf_oauth_expiration_minutes: 60
|
| 9 |
---
|
| 10 |
|
| 11 |
-
|
| 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 steering/acceleration networks within the current worker limits are supported.
|
| 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.
|
|
|
|
|
|
|
|
|
| 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 steering/acceleration networks within the current worker limits are supported.
|
| 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 |
+
|
| 17 |
+
Feedback issues: https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new.
|
RELEASE_MANIFEST.json
CHANGED
|
@@ -2,19 +2,20 @@
|
|
| 2 |
"backend": "cpu+zerogpu",
|
| 3 |
"files": {
|
| 4 |
".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
|
| 5 |
-
"BETA_TESTING.md": "
|
| 6 |
"BINARY_PROVENANCE.json": "1116e1757afc6c8629cb2d957e3d77380fe4f7e3186c3832d16a5a08abce6aa8",
|
| 7 |
-
"
|
| 8 |
-
"
|
| 9 |
-
"
|
|
|
|
| 10 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 11 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 12 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 13 |
-
"README.md": "
|
| 14 |
"STORAGE_BOUNDARY.md": "9a1ffb5854230690dba3f0895f9a8e570716de47be2c553de13a6892dd740015",
|
| 15 |
-
"TRACK_LIBRARY.md": "
|
| 16 |
"UPSTREAM.json": "40a2f31fa9abc11e47e247c56909b93b587d1f5be524ab158b24f1f9eed93765",
|
| 17 |
-
"app.py": "
|
| 18 |
"app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
|
| 19 |
"assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
|
| 20 |
"assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
|
|
@@ -52,12 +53,12 @@
|
|
| 52 |
"builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 53 |
"builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 54 |
"builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 55 |
-
"client.js": "
|
| 56 |
"delivery.py": "07453999c3831a16e8b1fcc2b4ae5fb28beb7d3952a3fae8de65d16eb6f11e5b",
|
| 57 |
"gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
|
| 58 |
-
"hf-auth.js": "
|
| 59 |
"hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
|
| 60 |
-
"index.html": "
|
| 61 |
"requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
|
| 62 |
"server.py": "de98db424b96a4fbab7ce5b98ee42a94e846e2b3f317593e2346c5f87489ede8",
|
| 63 |
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
|
|
|
| 2 |
"backend": "cpu+zerogpu",
|
| 3 |
"files": {
|
| 4 |
".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
|
| 5 |
+
"BETA_TESTING.md": "c2d4bc2eff0f87144a862282f20585868c95533103221f5d42726242b2eeba21",
|
| 6 |
"BINARY_PROVENANCE.json": "1116e1757afc6c8629cb2d957e3d77380fe4f7e3186c3832d16a5a08abce6aa8",
|
| 7 |
+
"CUDA_REFERENCE.md": "56a07521fc3d6acd11e3b3c110293d1a5ff710d1b7d7b93115e7b98d5ee7c256",
|
| 8 |
+
"DATA_POLICY.md": "38da17f8528ede1ef1850e98832f75ba35ebdc86a0cde87e27674eb0ff9c7a7f",
|
| 9 |
+
"FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
|
| 10 |
+
"FRONTEND_SOURCE.json": "4a6b79b38053a0db37eb36b6e7209a14ad7f9f505c373003b89f950fd0ff4654",
|
| 11 |
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 12 |
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 13 |
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 14 |
+
"README.md": "b41c614f81339e6392a018ba7133211a42e0416eb03544a6d54ac34efc7daa81",
|
| 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",
|
|
|
|
| 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": "b6c2e0439bc1e4cf55c5e751e497e842e1e911b229f7480d7b1e04dea246536f",
|
| 57 |
"delivery.py": "07453999c3831a16e8b1fcc2b4ae5fb28beb7d3952a3fae8de65d16eb6f11e5b",
|
| 58 |
"gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
|
| 59 |
+
"hf-auth.js": "d5cf17b961d1f2efa9d4648d33ba86a148eff0d542c74a121710c4df35c92936",
|
| 60 |
"hf_identity.py": "6993d0238ada835606dbdc3275c17a3fe5a5cac5ad2156ab78230acf2d051eba",
|
| 61 |
+
"index.html": "aeb602565bf2da9d40cb6c3aae0b6e713b89e79a81557fed3e7f3dd8d16f195c",
|
| 62 |
"requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
|
| 63 |
"server.py": "de98db424b96a4fbab7ce5b98ee42a94e846e2b3f317593e2346c5f87489ede8",
|
| 64 |
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
TRACK_LIBRARY.md
CHANGED
|
@@ -23,7 +23,8 @@ 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
|
|
|
|
| 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
|
|
|
|
| 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 canvas preview shows tile layout and asphalt, dirt, and ice terrain. It does
|
| 27 |
+
not show collision geometry or prove that the replica matches native physics.
|
| 28 |
|
| 29 |
The public app exposes only catalog-listed IDs and hash-checked replica bytes.
|
| 30 |
No directory browsing, caller-selected paths, remote track URLs or extraction
|
app.py
CHANGED
|
@@ -17,6 +17,7 @@ from fastapi.responses import FileResponse,JSONResponse
|
|
| 17 |
from app_release import ROOT,cpu_worker,verify_package
|
| 18 |
from gpu_tickets import InputTickets
|
| 19 |
from server import create_app
|
|
|
|
| 20 |
from worker import run_native,track_input,network_input
|
| 21 |
from training_config import validate_config
|
| 22 |
from build_info import build_identity
|
|
@@ -90,8 +91,16 @@ def build_app(cuda_call):
|
|
| 90 |
if not admission.acquire(blocking=False):raise ValueError('GPU worker busy')
|
| 91 |
try:
|
| 92 |
track,network,automatic,*config=tickets.take(ticket)
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
finally:admission.release()
|
| 96 |
|
| 97 |
@app.api(name='visitor_identity',api_visibility='undocumented')
|
|
|
|
| 17 |
from app_release import ROOT,cpu_worker,verify_package
|
| 18 |
from gpu_tickets import InputTickets
|
| 19 |
from server import create_app
|
| 20 |
+
from delivery import CapacityExceeded
|
| 21 |
from worker import run_native,track_input,network_input
|
| 22 |
from training_config import validate_config
|
| 23 |
from build_info import build_identity
|
|
|
|
| 91 |
if not admission.acquire(blocking=False):raise ValueError('GPU worker busy')
|
| 92 |
try:
|
| 93 |
track,network,automatic,*config=tickets.take(ticket)
|
| 94 |
+
try:
|
| 95 |
+
payload,report=cuda_call(track,network,*config)
|
| 96 |
+
return {**base.state.results.publish(payload,automatic),'backend':'gpu','report':report}
|
| 97 |
+
except CapacityExceeded:
|
| 98 |
+
raise ValueError('Result capacity reached; no result was published.') from None
|
| 99 |
+
except Exception:
|
| 100 |
+
# Gradio logs callback exceptions. Keep native/provider details out
|
| 101 |
+
# of both logs and the browser-facing error while preserving the
|
| 102 |
+
# UI's separate pending-ticket cleanup check.
|
| 103 |
+
raise ValueError('GPU processing failed; no result was published.') from None
|
| 104 |
finally:admission.release()
|
| 105 |
|
| 106 |
@app.api(name='visitor_identity',api_visibility='undocumented')
|
client.js
CHANGED
|
@@ -5,6 +5,7 @@ let busy = false;
|
|
| 5 |
let localResult = null;
|
| 6 |
let capabilitiesReady = false;
|
| 7 |
let gpuTransport = null;
|
|
|
|
| 8 |
let gradioClient = null;
|
| 9 |
let stagedNetwork = null;
|
| 10 |
let batchActive = false;
|
|
@@ -29,7 +30,7 @@ function buttons() {
|
|
| 29 |
window.HFAuth?.setBusy(busy || !!job);
|
| 30 |
window.setTrainingBusy?.(busy || !!job);
|
| 31 |
window.setEditorBusy?.(busy || !!job);
|
| 32 |
-
$('run').disabled = busy || !!job || !capabilitiesReady || !networkSource();
|
| 33 |
$('backend').disabled = busy || !!job || !capabilitiesReady;
|
| 34 |
$('download').disabled = busy || !job;
|
| 35 |
$('erase').disabled = busy || !job;
|
|
@@ -38,11 +39,20 @@ function buttons() {
|
|
| 38 |
$('forgetLocal').disabled = busy || !localResult;
|
| 39 |
$('track').disabled=busy || !!job;
|
| 40 |
$('network').disabled=busy || !!job;
|
| 41 |
-
if($('batch_start'))$('batch_start').disabled=busy || !!job || !capabilitiesReady;
|
| 42 |
if($('batch_stop'))$('batch_stop').disabled=!batchActive || batchStopRequested;
|
| 43 |
if($('run_export'))$('run_export').disabled=busy || !runReceipt;
|
| 44 |
if($('batch_export'))$('batch_export').disabled=busy || !batchReceipt;
|
| 45 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
function saveLocal() {
|
| 47 |
if(!localResult)return;
|
| 48 |
const link=document.createElement('a'),url=URL.createObjectURL(localResult);
|
|
@@ -197,7 +207,7 @@ $('download').onclick = async () => {
|
|
| 197 |
finally {busy=false; buttons();}
|
| 198 |
};
|
| 199 |
$('erase').onclick=async()=>{
|
| 200 |
-
if(!
|
| 201 |
busy=true; buttons();
|
| 202 |
try {await request('/api/jobs/'+job.id,{method:'DELETE',headers:headers()}); job=null; say('Server result deleted. Local files are unaffected.');}
|
| 203 |
catch(error){say(error.message);}
|
|
@@ -286,8 +296,10 @@ async function connect(){
|
|
| 286 |
$('buildLabel').textContent='Build: '+(appBuild?.build_id?.slice(0,25)??'Unavailable — include the app URL in feedback');
|
| 287 |
$('buildLabel').title=appBuild?.build_id??'';
|
| 288 |
}
|
|
|
|
| 289 |
gpuTransport=capabilities.gpu_transport??null;
|
| 290 |
-
$('gpuOption').disabled=!
|
|
|
|
| 291 |
$('backendNote').textContent=capabilities.gpu?(hostedStandalone?'CPU is anonymous. GPU may use a limited anonymous allowance or your optional HF account allowance.':'CPU is anonymous. GPU requires an available HF allowance.'):'CPU training is ready; no sign-in or GPU allowance needed.';
|
| 292 |
$('gpuAccount').hidden=!capabilities.gpu;
|
| 293 |
$('computeBlock').hidden=!capabilities.gpu;
|
|
@@ -295,7 +307,7 @@ async function connect(){
|
|
| 295 |
say('Connected. Choose your track and network, then run the test.');
|
| 296 |
} catch(error) {
|
| 297 |
$('connectionRecovery').hidden=false;
|
| 298 |
-
capabilitiesReady=false;
|
| 299 |
$('backendNote').textContent='Connection unavailable — training is disabled.';
|
| 300 |
say('Could not reach this app. Retry the public beta app address: https://tiga-rce-ald-tao-gpu.hf.space/. The HF repository page is restricted in Protected mode. No run was started.');
|
| 301 |
} finally {clearTimeout(timeout);$('retry').disabled=false;}
|
|
|
|
| 5 |
let localResult = null;
|
| 6 |
let capabilitiesReady = false;
|
| 7 |
let gpuTransport = null;
|
| 8 |
+
let gpuAvailable = false;
|
| 9 |
let gradioClient = null;
|
| 10 |
let stagedNetwork = null;
|
| 11 |
let batchActive = false;
|
|
|
|
| 30 |
window.HFAuth?.setBusy(busy || !!job);
|
| 31 |
window.setTrainingBusy?.(busy || !!job);
|
| 32 |
window.setEditorBusy?.(busy || !!job);
|
| 33 |
+
$('run').disabled = busy || !!job || !capabilitiesReady || !networkSource() || ($('backend').value==='gpu'&&!gpuAvailable);
|
| 34 |
$('backend').disabled = busy || !!job || !capabilitiesReady;
|
| 35 |
$('download').disabled = busy || !job;
|
| 36 |
$('erase').disabled = busy || !job;
|
|
|
|
| 39 |
$('forgetLocal').disabled = busy || !localResult;
|
| 40 |
$('track').disabled=busy || !!job;
|
| 41 |
$('network').disabled=busy || !!job;
|
| 42 |
+
if($('batch_start'))$('batch_start').disabled=busy || !!job || !capabilitiesReady || ($('backend').value==='gpu'&&!gpuAvailable);
|
| 43 |
if($('batch_stop'))$('batch_stop').disabled=!batchActive || batchStopRequested;
|
| 44 |
if($('run_export'))$('run_export').disabled=busy || !runReceipt;
|
| 45 |
if($('batch_export'))$('batch_export').disabled=busy || !batchReceipt;
|
| 46 |
}
|
| 47 |
+
$('backend').addEventListener('change',buttons);
|
| 48 |
+
const feedbackLink=$('feedbackLink');
|
| 49 |
+
feedbackLink?.addEventListener('click',()=>{
|
| 50 |
+
const url=new URL('https://github.com/seeker-cyber-maker/driving_sim_rs/issues/new');
|
| 51 |
+
const browser=navigator.userAgent||'Not reported';
|
| 52 |
+
const body=['Build: '+(appBuild?.build_id??'Not reported'),'Browser and OS: '+browser,'Selected backend: '+$('backend').value.toUpperCase(),'','What happened?'].join('\n');
|
| 53 |
+
url.searchParams.set('title','ALD beta problem report');url.searchParams.set('body',body);
|
| 54 |
+
feedbackLink.href=url.href;
|
| 55 |
+
});
|
| 56 |
function saveLocal() {
|
| 57 |
if(!localResult)return;
|
| 58 |
const link=document.createElement('a'),url=URL.createObjectURL(localResult);
|
|
|
|
| 207 |
finally {busy=false; buttons();}
|
| 208 |
};
|
| 209 |
$('erase').onclick=async()=>{
|
| 210 |
+
if(!await window.appConfirm('Delete remaining server-side result and revoke download access? Local files are unaffected.',{heading:'Delete server result',confirmLabel:'Delete result',danger:true}))return;
|
| 211 |
busy=true; buttons();
|
| 212 |
try {await request('/api/jobs/'+job.id,{method:'DELETE',headers:headers()}); job=null; say('Server result deleted. Local files are unaffected.');}
|
| 213 |
catch(error){say(error.message);}
|
|
|
|
| 296 |
$('buildLabel').textContent='Build: '+(appBuild?.build_id?.slice(0,25)??'Unavailable — include the app URL in feedback');
|
| 297 |
$('buildLabel').title=appBuild?.build_id??'';
|
| 298 |
}
|
| 299 |
+
gpuAvailable=capabilities.gpu===true;
|
| 300 |
gpuTransport=capabilities.gpu_transport??null;
|
| 301 |
+
$('gpuOption').disabled=!gpuAvailable;
|
| 302 |
+
if(!gpuAvailable)$('backend').value='cpu';
|
| 303 |
$('backendNote').textContent=capabilities.gpu?(hostedStandalone?'CPU is anonymous. GPU may use a limited anonymous allowance or your optional HF account allowance.':'CPU is anonymous. GPU requires an available HF allowance.'):'CPU training is ready; no sign-in or GPU allowance needed.';
|
| 304 |
$('gpuAccount').hidden=!capabilities.gpu;
|
| 305 |
$('computeBlock').hidden=!capabilities.gpu;
|
|
|
|
| 307 |
say('Connected. Choose your track and network, then run the test.');
|
| 308 |
} catch(error) {
|
| 309 |
$('connectionRecovery').hidden=false;
|
| 310 |
+
capabilitiesReady=false;gpuAvailable=false;gpuTransport=null;$('backend').value='cpu';$('gpuOption').disabled=true;buttons();
|
| 311 |
$('backendNote').textContent='Connection unavailable — training is disabled.';
|
| 312 |
say('Could not reach this app. Retry the public beta app address: https://tiga-rce-ald-tao-gpu.hf.space/. The HF repository page is restricted in Protected mode. No run was started.');
|
| 313 |
} finally {clearTimeout(timeout);$('retry').disabled=false;}
|
hf-auth.js
CHANGED
|
@@ -40,7 +40,7 @@
|
|
| 40 |
node('hfSignIn').onclick=async()=>{
|
| 41 |
if(locked||exchanging||!ready)return;
|
| 42 |
if((node('track').files.length||node('network').files.length) &&
|
| 43 |
-
!
|
| 44 |
exchanging=true;render();
|
| 45 |
try{
|
| 46 |
const state={};
|
|
|
|
| 40 |
node('hfSignIn').onclick=async()=>{
|
| 41 |
if(locked||exchanging||!ready)return;
|
| 42 |
if((node('track').files.length||node('network').files.length) &&
|
| 43 |
+
!(await window.appConfirm('HF sign-in navigates away. Selected files and unsaved editor changes are lost; saved recipes remain. Continue, then reselect files?',{heading:'Continue to HF sign-in',confirmLabel:'Continue to sign in'})))return;
|
| 44 |
exchanging=true;render();
|
| 45 |
try{
|
| 46 |
const state={};
|
index.html
CHANGED
|
@@ -1,8 +1,34 @@
|
|
| 1 |
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
|
| 2 |
<style>
|
| 3 |
:root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
|
| 4 |
-
.tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}@media(max-width:850px){.map{min-height:0}}</style>
|
| 5 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
<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 steering/acceleration, speed/raycast sensors, and 2–4 layers of up to 16 nodes.</p>
|
| 7 |
<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>
|
| 8 |
<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>
|
|
@@ -249,10 +275,10 @@
|
|
| 249 |
window.getBatchPlan=()=>window.BatchTraining.plan(read(),q('batch_slot').value);
|
| 250 |
const action=fn=>async()=>{try{await fn();}catch(error){message('Not completed: '+error.message);}};
|
| 251 |
q('recipe_apply_draft').onclick=action(()=>{applySettings(JSON.parse(q('recipe_draft').value));q('preset').value='custom';q('reward_preset').value='custom';message('Draft applied to the training form. No run started.');});
|
| 252 |
-
q('recipe_save').onclick=action(()=>{
|
| 253 |
const book=read(),slot=q('recipe_slot').value;
|
| 254 |
const next=api.validate({...book,recipes:[...book.recipes.filter(r=>r.slot!==slot),{slot,name:q('recipe_name').value,settings:currentSettings()}]});
|
| 255 |
-
if(book.recipes.some(r=>r.slot===slot)&&!
|
| 256 |
store.save(next);message('Saved slot '+slot+' in this browser.');
|
| 257 |
});
|
| 258 |
q('recipe_load').onclick=action(()=>{
|
|
@@ -266,14 +292,14 @@
|
|
| 266 |
message('Recipe export requested. No tracks, networks, results or credentials are included by the application.');
|
| 267 |
});
|
| 268 |
q('recipe_import').onchange=action(async()=>{
|
| 269 |
-
const
|
| 270 |
const book=api.parse(await file.text());
|
| 271 |
-
if(!
|
| 272 |
if(!store)throw Error('Browser storage unavailable');store.save(book);
|
| 273 |
message('Imported '+book.recipes.length+' recipes locally. No run was started.');q('recipe_import').value='';
|
| 274 |
});
|
| 275 |
-
q('recipe_clear').onclick=action(()=>{
|
| 276 |
-
if(!
|
| 277 |
if(!store)throw Error('Browser storage unavailable');store.clear();message('Local recipes cleared. Server data and downloads are unaffected.');
|
| 278 |
});
|
| 279 |
q('batch_save').disabled=false;q('batch_load').disabled=false;
|
|
@@ -282,11 +308,11 @@
|
|
| 282 |
q('queue_add').onclick=()=>{
|
| 283 |
const text=q('batch_recipe_sequence').value.trim();q('batch_recipe_sequence').value=text?text+', '+q('batch_add_recipe').value:q('batch_add_recipe').value;
|
| 284 |
};
|
| 285 |
-
q('batch_save').onclick=action(()=>{
|
| 286 |
const book=read(),slot=q('batch_slot').value;
|
| 287 |
const runs=q('batch_recipe_sequence').value.split(',').map(s=>s.trim().toUpperCase());
|
| 288 |
const next=api.validate({...book,batches:[...book.batches.filter(b=>b.slot!==slot),{slot,name:q('batch_name').value,carry:q('carry').checked,runs}]});
|
| 289 |
-
if(book.batches.some(b=>b.slot===slot)&&!
|
| 290 |
store.save(next);message('Batch '+slot+' saved locally.');
|
| 291 |
});
|
| 292 |
q('batch_load').onclick=action(()=>{
|
|
|
|
| 1 |
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
|
| 2 |
<style>
|
| 3 |
:root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
|
| 4 |
+
.tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}@media(max-width:850px){.map{min-height:0}}dialog#appConfirm{box-sizing:border-box;width:min(92vw,440px);border:1px solid #54718d;border-radius:16px;padding:24px;background:#152233;color:#e5edf5;box-shadow:0 24px 80px #000b}dialog#appConfirm::backdrop{background:#02060bcc}#appConfirm h2{margin:0 0 10px}#appConfirm p{line-height:1.55;color:#c4d3e1;white-space:pre-wrap}#appConfirm .actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:22px}#appConfirm button{min-width:100px}#appConfirm button.danger{background:#8e3b37;color:#fff;border-color:#d7837e}</style>
|
| 5 |
+
<dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
|
| 6 |
+
<h2 id="appConfirmTitle">Confirm action</h2>
|
| 7 |
+
<p id="appConfirmMessage"></p>
|
| 8 |
+
<div class="actions"><button id="appConfirmCancel" type="button">Cancel</button><button id="appConfirmAccept" type="button">Continue</button></div>
|
| 9 |
+
</dialog>
|
| 10 |
+
<script>
|
| 11 |
+
(() => {
|
| 12 |
+
const dialog=document.getElementById('appConfirm'),title=document.getElementById('appConfirmTitle');
|
| 13 |
+
const message=document.getElementById('appConfirmMessage'),cancel=document.getElementById('appConfirmCancel');
|
| 14 |
+
const accept=document.getElementById('appConfirmAccept');
|
| 15 |
+
let finish=null,returnFocus=null;
|
| 16 |
+
dialog.addEventListener('close',()=>{
|
| 17 |
+
const resolve=finish;finish=null;
|
| 18 |
+
if(resolve)resolve(dialog.returnValue==='confirm');
|
| 19 |
+
if(returnFocus?.isConnected)returnFocus.focus();returnFocus=null;
|
| 20 |
+
});
|
| 21 |
+
cancel.addEventListener('click',()=>dialog.close('cancel'));
|
| 22 |
+
accept.addEventListener('click',()=>dialog.close('confirm'));
|
| 23 |
+
window.appConfirm=(text,{heading='Confirm action',confirmLabel='Continue',cancelLabel='Cancel',danger=false}={})=>{
|
| 24 |
+
if(finish) return Promise.resolve(false);
|
| 25 |
+
returnFocus=document.activeElement;title.textContent=heading;message.textContent=text;
|
| 26 |
+
accept.textContent=confirmLabel;cancel.textContent=cancelLabel;accept.classList.toggle('danger',danger);
|
| 27 |
+
return new Promise(resolve=>{finish=resolve;dialog.showModal();cancel.focus();});
|
| 28 |
+
};
|
| 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 steering/acceleration, speed/raycast sensors, and 2–4 layers of up to 16 nodes.</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>
|
|
|
|
| 275 |
window.getBatchPlan=()=>window.BatchTraining.plan(read(),q('batch_slot').value);
|
| 276 |
const action=fn=>async()=>{try{await fn();}catch(error){message('Not completed: '+error.message);}};
|
| 277 |
q('recipe_apply_draft').onclick=action(()=>{applySettings(JSON.parse(q('recipe_draft').value));q('preset').value='custom';q('reward_preset').value='custom';message('Draft applied to the training form. No run started.');});
|
| 278 |
+
q('recipe_save').onclick=action(async()=>{
|
| 279 |
const book=read(),slot=q('recipe_slot').value;
|
| 280 |
const next=api.validate({...book,recipes:[...book.recipes.filter(r=>r.slot!==slot),{slot,name:q('recipe_name').value,settings:currentSettings()}]});
|
| 281 |
+
if(book.recipes.some(r=>r.slot===slot)&&!(await window.appConfirm('Replace recipe slot '+slot+' on this device?',{heading:'Replace saved recipe',confirmLabel:'Replace'})))return;
|
| 282 |
store.save(next);message('Saved slot '+slot+' in this browser.');
|
| 283 |
});
|
| 284 |
q('recipe_load').onclick=action(()=>{
|
|
|
|
| 292 |
message('Recipe export requested. No tracks, networks, results or credentials are included by the application.');
|
| 293 |
});
|
| 294 |
q('recipe_import').onchange=action(async()=>{
|
| 295 |
+
const input=q('recipe_import'),file=input.files[0];if(!file)return;input.value='';if(file.size>32768)throw Error('Recipe file exceeds 32 KB');
|
| 296 |
const book=api.parse(await file.text());
|
| 297 |
+
if(!(await window.appConfirm('Replace this browser’s recipe library with '+book.recipes.length+' imported recipes? Export a backup first if needed.',{heading:'Import recipe library',confirmLabel:'Replace library'})))return;
|
| 298 |
if(!store)throw Error('Browser storage unavailable');store.save(book);
|
| 299 |
message('Imported '+book.recipes.length+' recipes locally. No run was started.');q('recipe_import').value='';
|
| 300 |
});
|
| 301 |
+
q('recipe_clear').onclick=action(async()=>{
|
| 302 |
+
if(!(await window.appConfirm('Clear saved recipes and batches for this app on this device? Server run data and downloaded files are unaffected.',{heading:'Clear local recipes and batches',confirmLabel:'Clear local data',danger:true})))return;
|
| 303 |
if(!store)throw Error('Browser storage unavailable');store.clear();message('Local recipes cleared. Server data and downloads are unaffected.');
|
| 304 |
});
|
| 305 |
q('batch_save').disabled=false;q('batch_load').disabled=false;
|
|
|
|
| 308 |
q('queue_add').onclick=()=>{
|
| 309 |
const text=q('batch_recipe_sequence').value.trim();q('batch_recipe_sequence').value=text?text+', '+q('batch_add_recipe').value:q('batch_add_recipe').value;
|
| 310 |
};
|
| 311 |
+
q('batch_save').onclick=action(async()=>{
|
| 312 |
const book=read(),slot=q('batch_slot').value;
|
| 313 |
const runs=q('batch_recipe_sequence').value.split(',').map(s=>s.trim().toUpperCase());
|
| 314 |
const next=api.validate({...book,batches:[...book.batches.filter(b=>b.slot!==slot),{slot,name:q('batch_name').value,carry:q('carry').checked,runs}]});
|
| 315 |
+
if(book.batches.some(b=>b.slot===slot)&&!(await window.appConfirm('Replace saved batch slot '+slot+'?',{heading:'Replace saved batch',confirmLabel:'Replace'})))return;
|
| 316 |
store.save(next);message('Batch '+slot+' saved locally.');
|
| 317 |
});
|
| 318 |
q('batch_load').onclick=action(()=>{
|