A browser-based self-driving car simulator built from scratch with vanilla JavaScript. Cars use a feedforward neural network to learn how to navigate a road and avoid traffic through an evolutionary approach.
This project was created as a study exercise to understand how neural networks work at a fundamental level — specifically how Inputs, Biases, and Outputs interact to produce decisions, much like the building blocks behind large language models and other AI systems.
The core of the project is a custom feedforward neural network with the following architecture:
Input Layer (5 neurons) --> Hidden Layer (6 neurons) --> Output Layer (4 neurons)
[Sensor readings] [Weighted sums + Bias] [Driving controls]
Forward propagation follows these steps for each neuron:
- Compute the weighted sum of all inputs:
sum = input[0] * weight[0] + input[1] * weight[1] + ... - Compare against the neuron's bias value
- If
sum > bias, the neuron fires (output = 1), otherwise it stays off (output = 0)
This binary threshold activation is intentionally simple, making it easier to observe how weights and biases shape the network's behavior.
Each car has 5 sensor rays spread across a 90-degree arc in front of it. These rays detect obstacles (road borders and traffic) and produce a normalized distance value:
1.0= obstacle is very close (touching the car)0.0= no obstacle detected within range- Values in between represent proportional distance
These 5 values are the neural network's only perception of the world.
Each neuron in the hidden and output layers has a bias value (randomly initialized between -1 and 1). The bias acts as a threshold that determines how easily a neuron activates:
- A low bias means the neuron fires easily (needs less input signal)
- A high bias means the neuron requires stronger input to activate
The bias is what allows the network to make non-trivial decisions. Without it, the network could only represent linear mappings from inputs to outputs.
The 4 output neurons map directly to car controls:
| Output | Action |
|---|---|
| 0 | Forward |
| 1 | Left |
| 2 | Right |
| 3 | Reverse |
Each output is binary (0 or 1), so the car either applies a control or it doesn't.
The learning mechanism uses an evolutionary / genetic algorithm approach rather than backpropagation:
- Spawn multiple cars (default 100, configurable via UI) at the starting position, each with a neural network
- If a previously saved brain exists, the first car gets an exact copy and the rest get mutated variants
- Mutation works by blending each weight and bias toward a new random value:
new = lerp(old, random, amount)— the mutation rate is adjustable (1%–50%, default 10%) - All cars drive simultaneously — the one that travels the furthest without crashing (highest fitness = greatest negative Y position) is considered the best
- Save the best car's brain to
localStorageand repeat
Over many generations, the network converges on weights and biases that produce effective driving behavior.
index.html Entry point — two canvases, header controls, info cards, and settings
style.css Custom dark theme (Space Grotesk + JetBrains Mono, CSS grid layout)
js/
network.js NeuralNetwork and Level classes (feedforward + mutation)
car.js Car physics, collision detection, and neural network integration
sensor.js Raycasting system (5 rays, 150px range, 90-degree spread)
visualizer.js Real-time neural network graph on canvas
road.js Road geometry and lane calculations (3-lane road)
utils.js Linear interpolation, line intersection, polygon collision
main.js Application loop, event listeners, car generation, animation
No build tools or dependencies required. Open index.html in a browser:
# Using Python
python3 -m http.server 8080
# Using Node.js
npx serve .Then open http://localhost:8080 in your browser.
The interface uses a two-column layout:
- Left — Simulation area: Top-down view showing the road, AI cars (cyan, semi-transparent) with the best car highlighted, and traffic cars (magenta). An overlay displays live stats: Generation count, Cars Alive, and Best Distance. Below the canvas, three info cards explain Inputs, Bias, and Outputs.
- Right — Network panel: Live neural network visualization with color-coded connections (yellow = positive weight, magenta = negative weight) and active neuron highlighting (cyan glow). Below the graph: output indicators (Forward, Left, Right, Reverse), simulation settings (number of cars, mutation rate slider), and a network legend.
| Button | Action |
|---|---|
| Save Best | Persist the best car's brain to localStorage |
| Reset Brain | Remove the saved brain and start fresh |
| New Generation | Restart with a new generation of cars |
| Setting | Description |
|---|---|
| Number of Cars | How many AI cars to spawn per generation (1–500) |
| Mutation Rate | How aggressively to mutate saved brains (1%–50%) |
- HTML5 Canvas for rendering
- Vanilla JavaScript (ES6+ with classes and private methods)
- Custom CSS with CSS Grid layout
- Google Fonts (Space Grotesk, JetBrains Mono)
localStoragefor model persistence- No external ML libraries — the neural network is implemented from scratch