From 2025d444de43ac758fd01323034af90bcc0b80ec Mon Sep 17 00:00:00 2001 From: Ofer Shaal Date: Sun, 24 May 2026 21:04:18 -0400 Subject: [PATCH] Add Pure Local Sensors experiment + first-load UX improvements and fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduce 'Pure Local Sensors' mode (?pure-local=1) that zeros lf/lr track-orientation features so the brain only receives raw rays + speed. - Add toggle in the πŸ§ͺ Experiments panel with URL sync and restart helper. - Improve first-load experience: collapse advanced panels, prominent Start button, one-time helpful hint after first start. - Fix visual bug where #ab-hud (A/B HUD) leaked dark horizontal lines on first load and after A/B toggle cycles (now uses robust .ab-hud-visible class + early hide). - Add dedicated ELI15 chapter for the pure-local experiment. - Add planning documents under docs/plans/ for future RL mode and policy capability enhancements. - Various ELI15 accuracy fixes and supporting screenshots for validation. --- AI-Car-Racer/buttonResponse.js | 14 ++ AI-Car-Racer/car.js | 15 +- AI-Car-Racer/eli15/chapters/lineage.js | 4 +- AI-Car-Racer/eli15/chapters/neural-network.js | 30 +-- .../eli15/chapters/pure-local-experiment.js | 30 +++ AI-Car-Racer/eli15/chapters/sensors.js | 4 +- .../eli15/chapters/what-is-this-project.js | 4 +- AI-Car-Racer/eli15/chapters/why-cars-crash.js | 10 +- AI-Car-Racer/eli15/index.js | 11 +- AI-Car-Racer/eli15/tour.js | 4 +- AI-Car-Racer/main.js | 81 ++++++- AI-Car-Racer/sim-worker.js | 1 + AI-Car-Racer/style.css | 24 +- AI-Car-Racer/uiPanels.js | 109 ++++++++- docs/plans/enhancing-policy-capabilities.md | 214 ++++++++++++++++++ docs/plans/reinforcement-learning-mode.md | 192 ++++++++++++++++ .../screenshots/ab-hud-toggle-fix.png | Bin 0 -> 116515 bytes .../screenshots/first-load-after-fix.png | Bin 0 -> 116846 bytes .../screenshots/first-load-fixed-abhud.png | Bin 0 -> 116515 bytes ...angle-checkpoints-left-focus-annotated.png | Bin 0 -> 197609 bytes .../triangle-checkpoints-left-focus.png | Bin 0 -> 189244 bytes .../triangle-v2-left-focus-annotated.png | Bin 0 -> 207775 bytes .../screenshots/triangle-v2-left-focus.png | Bin 0 -> 198645 bytes docs/validation/screenshots/two-lines.jpg | Bin 0 -> 8713 bytes .../validation/screenshots/vv-after-start.png | Bin 0 -> 125712 bytes docs/validation/screenshots/vv-first-load.png | Bin 0 -> 127103 bytes .../vv-headed-03-triangle-10cps-annotated.png | Bin 0 -> 206584 bytes .../vv-headed-03-triangle-10cps.png | Bin 0 -> 196801 bytes .../screenshots/vv-improved-first-load.png | Bin 0 -> 154373 bytes two-lines.jpg | Bin 0 -> 8713 bytes 30 files changed, 702 insertions(+), 45 deletions(-) create mode 100644 AI-Car-Racer/eli15/chapters/pure-local-experiment.js create mode 100644 docs/plans/enhancing-policy-capabilities.md create mode 100644 docs/plans/reinforcement-learning-mode.md create mode 100644 docs/validation/screenshots/ab-hud-toggle-fix.png create mode 100644 docs/validation/screenshots/first-load-after-fix.png create mode 100644 docs/validation/screenshots/first-load-fixed-abhud.png create mode 100644 docs/validation/screenshots/triangle-checkpoints-left-focus-annotated.png create mode 100644 docs/validation/screenshots/triangle-checkpoints-left-focus.png create mode 100644 docs/validation/screenshots/triangle-v2-left-focus-annotated.png create mode 100644 docs/validation/screenshots/triangle-v2-left-focus.png create mode 100644 docs/validation/screenshots/two-lines.jpg create mode 100644 docs/validation/screenshots/vv-after-start.png create mode 100644 docs/validation/screenshots/vv-first-load.png create mode 100644 docs/validation/screenshots/vv-headed-03-triangle-10cps-annotated.png create mode 100644 docs/validation/screenshots/vv-headed-03-triangle-10cps.png create mode 100644 docs/validation/screenshots/vv-improved-first-load.png create mode 100644 two-lines.jpg diff --git a/AI-Car-Racer/buttonResponse.js b/AI-Car-Racer/buttonResponse.js index dc1c5a3..f28471a 100644 --- a/AI-Car-Racer/buttonResponse.js +++ b/AI-Car-Racer/buttonResponse.js @@ -8,6 +8,20 @@ function pauseGame(){ btn.classList.remove('start-cta'); } window.__firstStart = false; + + // Gentle first-time onboarding hint (only shown once) + if (!localStorage.getItem('seenFirstStartHint')) { + localStorage.setItem('seenFirstStartHint', '1'); + setTimeout(() => { + try { + const hint = document.createElement('div'); + hint.style.cssText = 'position:fixed;bottom:12px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.78);color:#ddd;padding:6px 14px;border-radius:4px;font-size:12px;z-index:9999;white-space:nowrap;'; + hint.innerHTML = 'Demo running β€” cars are evolving. Use β€œβœοΈ Customize Track” or πŸ§ͺ Experiments for more options.'; + document.body.appendChild(hint); + setTimeout(() => { if (hint && hint.parentNode) hint.parentNode.removeChild(hint); }, 7000); + } catch (_) {} + }, 1400); + } // Halt / resume the worker's AI step loop too. Without this, sim-worker // would keep burning CPU while the user has paused β€” and on resume the // accumulator would stampede a huge backlog of physics steps at once. diff --git a/AI-Car-Racer/car.js b/AI-Car-Racer/car.js index 778e0e8..e867aa3 100644 --- a/AI-Car-Racer/car.js +++ b/AI-Car-Racer/car.js @@ -125,7 +125,14 @@ class Car{ // distance cue; see docs/plan/ruvector-proof/arch-a1/PROOF.md. const cpList = checkPointList; let lf = 0, lr = 0; - if (cpList && cpList.length){ + + // When pureLocalSensors is active, we deliberately give the brain + // ZERO information about where the next checkpoint is. + // This is the "embodied local signals only" mode for comparison. + // Guard works in both main thread (window) and Web Worker (self). + const isPureLocal = (typeof window !== 'undefined' && window.pureLocalSensors) || + (typeof self !== 'undefined' && self.pureLocalSensors); + if (!isPureLocal && cpList && cpList.length){ const passed = this.checkPointsPassed; const nextIdx = passed.length === 0 ? 0 @@ -139,11 +146,7 @@ class Car{ const s = Math.sin(this.angle), c = Math.cos(this.angle); const lfRaw = dx * s + dy * c; const lrRaw = dx * c - dy * s; - // Canvas diagonal as track-invariant scale. `road` is a - // global populated by main.js (or handleInit in the - // worker); both paths set `right` and `bottom` = canvas - // dims. Fallback constant guards the very-early frame - // before handleInit lands. + // Canvas diagonal as track-invariant scale. const W = (typeof road !== 'undefined' && road && road.right) ? (road.right - road.left) : 3200; const H = (typeof road !== 'undefined' && road && road.bottom) ? (road.bottom - road.top) : 1800; const D = Math.hypot(W, H); diff --git a/AI-Car-Racer/eli15/chapters/lineage.js b/AI-Car-Racer/eli15/chapters/lineage.js index e02dd92..05b6b7a 100644 --- a/AI-Car-Racer/eli15/chapters/lineage.js +++ b/AI-Car-Racer/eli15/chapters/lineage.js @@ -6,12 +6,12 @@ export default { oneLiner: 'parentIds + getLineage() reconstruct a brain\'s family tree on demand.', body: [ '

When a generation ends, the best car\'s brain gets archived β€” but we don\'t just', - 'save the 92 weights. We also save which brains it came from. Each', + 'save the 244 weights. We also save which brains it came from. Each', 'archive entry carries a parentIds: string[]: the ids of the seeds the GA', 'warm-started this batch from. Those parents have their own parents stored', 'alongside their weights. String enough of those together and you have a family', 'tree of neural networks.

', - '

ruvectorBridge.js:200 exposes getLineage(id, maxDepth = 6).', + '

ruvectorBridge.js:1338 exposes getLineage(id, maxDepth = 6).', 'Starting from any brain id, it walks parentIds backwards. When a brain has', 'multiple parents (the batch was seeded from multiple retrievals), it picks the parent', 'with the highest fitness β€” "the line of descent we credit this genome to". The', diff --git a/AI-Car-Racer/eli15/chapters/neural-network.js b/AI-Car-Racer/eli15/chapters/neural-network.js index c5af0fa..ad3f364 100644 --- a/AI-Car-Racer/eli15/chapters/neural-network.js +++ b/AI-Car-Racer/eli15/chapters/neural-network.js @@ -1,28 +1,28 @@ // eli15/chapters/neural-network.js -// The 92-weight 6β†’8β†’4 feed-forward network that decides W/A/S/D. +// The 244-weight 10β†’16β†’4 feed-forward network that decides W/A/S/D. export default { id: 'neural-network', - title: 'A brain made of 92 numbers', - oneLiner: 'Six sensor inputs β†’ eight hidden neurons β†’ four pedal/steer outputs.', + title: 'A brain made of 244 numbers', + oneLiner: 'Ten sensor inputs β†’ sixteen hidden neurons β†’ four pedal/steer outputs.', body: [ '

Every car carries a tiny neural network. It is almost comically small:', - '6 inputs β†’ 8 hidden neurons β†’ 4 outputs. See it in', + '10 inputs β†’ 16 hidden neurons β†’ 4 outputs. See it in', 'network.js (the Level and NeuralNetwork classes) and', - 'car.js:37-38 where the car wires it up.

', + 'car.js:41-42 where the car wires it up.

', '

"A neuron" here is just a weighted sum with a threshold. It multiplies each input', 'by a weight, adds them all up, and compares the total to a bias.', 'If the sum beats the bias, the neuron fires a 1. Otherwise a 0. That\'s it β€” no fancy', 'activation function, no backprop, no gradients. The whole network can be serialised', - 'as a flat Float32Array(92) β€” see brainCodec.js:2:', - 'FLAT_LENGTH = 92. Where does 92 come from? For each layer with in', + 'as a flat Float32Array(244) β€” see brainCodec.js:5:', + 'FLAT_LENGTH = 244. Where does 244 come from? For each layer with in', 'inputs and out outputs you need in Γ— out weights plus out biases:', - '(6Γ—8 + 8) + (8Γ—4 + 4) = 56 + 36 = 92.

', + '(10Γ—16 + 16) + (16Γ—4 + 4) = 176 + 68 = 244.

', '

The four outputs are Boolean: forward, reverse, left, right.', - 'The car presses the pedals whose neuron fired a 1. Combine that with the 5 rays', - '(plus 1 bias) from sensors and you get the whole perception-to-action pipeline', + 'The car presses the pedals whose neuron fired a 1. Combine that with the 7 rays + 3 features', + ' from sensors + car and you get the whole perception-to-action pipeline', 'in ~50 lines of JS.

', '

No learning happens inside the brain itself β€” the brain is just a lookup function.', - 'Learning happens across generations, by the genetic algorithm tweaking those 92', + 'Learning happens across generations, by the genetic algorithm tweaking those 244', 'numbers.

', '

Try it yourself

', '