No pretrained policy. No scripted gait. No walking animation.
Every step is produced by a randomly initialized neural network controlling four motors inside a Planck.js simulation.
StrideLab makes the learning process visible. A two-legged agent begins with random motor commands, falls repeatedly, and improves through neuroevolution. The interface shows live attempts, generation history, the validated distance champion, and a measured comparison against untrained random controllers.
The interesting part is not a polished walk cycle. It is watching coordinated movement emerge from selection, mutation, rigid-body dynamics, and a deliberately small neural network.
The deterministic headless test evaluates the saved champion and random controllers on the same six starting conditions.
| Controller | Mean distance |
|---|---|
| Evolved champion after 48 generations | 7.320 m |
| Untrained random baseline | 0.215 m |
That is a 34× distance advantage in the reproducible smoke test. The UI never invents progress: the saved champion changes only when a candidate travels farther on average across the fixed validation set.
npm run test:sim -- 48The articulated body contains a torso, two thighs, two shins, two feet, hip joints, knee joints, welded ankles, collisions, friction, gravity, joint limits, and bounded motor torque.
At every 60 Hz simulation step, a 16 → 12 → 4 tanh network receives:
- torso angle, angular velocity, height, and linear velocity;
- four joint angles and four joint speeds;
- left and right foot contact;
- forward motion information.
Its four outputs directly set the two hip and two knee motor speeds. There is no hidden phase controller or authored movement rule.
- Create a population of 32 randomly initialized neural networks.
- Simulate each controller from slightly varied starting poses.
- Reward forward distance, balance, and survival time.
- Penalize unnecessary mechanical work and stop an episode when the torso falls.
- Preserve strong candidates and create offspring through crossover and Gaussian mutation.
- Validate the farthest finalist on six fixed starts.
- Save a new champion only when its validated mean distance strictly increases.
Fast mode uses successive evaluation rounds without weakening champion validation:
32 controllers × start 1
↓ keep 16
16 controllers × start 2
↓ keep 8
8 controllers × start 3
↓
farthest finalist × 6 validation starts
Candidate evaluation is distributed across up to eight Web Workers. Physics, inference, and evolution stay off the React UI thread.
flowchart LR
UI[React interface] -->|commands| TW[Training worker]
TW -->|state + frames| UI
TW --> P[Population + evolution]
P --> W[Evaluation worker pool]
W --> S[Planck.js episodes]
S --> N[16 → 12 → 4 network]
N --> M[Hip + knee motors]
M --> S
TW -->|champion + history| LS[(localStorage)]
LS --> TW
- Watch attempts — renders the current physics episode in real time.
- Fast training — uses staged evaluation and up to eight workers.
- Performance chart — plots population mean and validated best distance.
- Measured comparison — evolved champion versus fresh random networks on identical starts.
- Replay best — loads the saved weights into a new physics world.
- Persistent progress — champion weights, history, and benchmark survive refreshes.
- Responsive UI — training never blocks the main browser thread.
Requirements: Node.js 20.19+ (or 22.12+) and npm.
git clone https://github.com/rezvvent/StrideLab.git
cd StrideLab
npm ci
npm run devOpen the URL printed by Vite, normally http://localhost:5173.
| Command | Purpose |
|---|---|
npm run dev |
Start the development server |
npm run build |
Type-check and create a production build |
npm run preview |
Preview the production build locally |
npm run lint |
Run ESLint |
npm run test:sim -- 48 |
Run the deterministic learning benchmark |
| Control | Behavior |
|---|---|
| Start / Resume | Continue evolution |
| Pause | Stop after the current worker operation and persist progress |
| Reset training | Clear the champion and begin from a new random population |
| Replay best | Run the validated champion in a fresh simulation |
| Watch attempts | Prefer real-time visualization |
| Fast training | Prefer maximum learning throughput |
src/
├── components/ Canvas, chart, benchmark, and controls
├── hooks/useTrainingWorker.ts UI ↔ worker protocol and persistence
├── sim/
│ ├── biped.ts Body construction, physics, observations, reward
│ ├── evolution.ts Population, staged evaluation, mutation settings
│ ├── network.ts Neural inference and genome operators
│ ├── rng.ts Deterministic seeded randomness
│ └── types.ts Shared worker and simulation types
└── workers/
├── training.worker.ts Training state machine and champion validation
└── evaluation.worker.ts Parallel Planck.js episode evaluation
scripts/sim-smoke.ts Reproducible end-to-end learning benchmark
- New projects begin with random weights.
- The controller receives only simulation observations.
- All motion comes from bounded joint motors and Planck.js dynamics.
- Training and random baselines use the same validation starts.
- The comparison panel displays simulation output, never placeholder metrics.
- A generation may fail to improve; the champion line stays flat rather than reporting fake progress.
Built as an interactive experiment in neuroevolution, browser concurrency, and honest ML visualization.
