Building a Traffic Wave Simulator with Claude and Gemini

Traffic waves—those infuriating “phantom” jams where traffic stops for no apparent reason—are a fascinating study in emergent behavior. Recently, I set out to build an interactive simulation of this phenomenon. Rather than writing it entirely from scratch, I decided to test a multi-AI collaborative workflow: using Gemini (plus) and Claude (free) together, playing to their respective strengths across extraction, fast prototyping, and code refinement.

Here is how the project evolved from a single YouTube video into a fully functional simulation, along with the prompts, iterations, and lessons learned along the way.

Phase 1: Video to Specification (Gemini)

This video shows a nifty experiment on how traffic waves form. Unfortunately, it does not explain the theory:

The project actually began with this real-world demonstration of a traffic wave on YouTube (watch it on a separate tab), which does explain the theory. Too much, actually:

I wanted to capture the core physical rules driving the behavior—vehicle spacing, acceleration delays, and human reaction time—and translate them into a clear software specification.

I called Gemini via its button on Chrome while displaying the second video, and asked it to analyze the video and generate a detailed prompt that could be fed into a coding model to reproduce the effect in JavaScript/HTML5 Canvas.

The Video-to-Prompt Request:

I'd like to make a simulation based in part on this video. Give me a prompt that I can feed into an LLM chat to do coding.

Gemini extracted the visual mechanics well, translating observed physical behaviors into programmatic requirements (ring topology, car-following logic, and variable reaction times).

Phase 2: Rapid Prototyping (Claude)

With a structured specification in hand, I handed the prompt over to Claude to generate the initial prototype.

The Initial Generation Prompt:

Act as an expert software engineer and physics simulation developer. I want to build an interactive, browser-based traffic simulation (HTML/CSS/JavaScript with HTML5 Canvas) that demonstrates traffic wave formation and wave damping (smoothing out traffic jams).

Please write the complete code for a single-file prototype (`index.html`) implementing the following:

### Core Requirements & Physics Models
1. **Track Geometry:**
– A single-lane circular track (loop) or long straight road with periodic boundary conditions.
2. **Vehicle Modeling & Following Behavior:**
– Model vehicles using standard micro-traffic driver behavior, such as the **Intelligent Driver Model (IDM)** (or an equivalent car-following model).
– Parameters for each vehicle should include position, velocity, maximum acceleration, comfortable deceleration, desired speed, and minimum headway distance.
3. **Traffic Jam Formation (Oscillations):**
– Introduce slight driver imperfections (e.g., delayed reaction times, slight over-braking, or random small speed fluctuations/phantom slowdowns) so that backward-propagating traffic jam waves form naturally when vehicle density is sufficiently high.
4. **Wave Damper Vehicle Implementation:**
– Allow designated “Wave Damper” vehicles (visually highlighted, e.g., blue or green vs. red/gray standard cars).
– Damper vehicles should maintain a larger, adaptive follow distance and smoothly match the average traffic speed rather than abruptly braking or accelerating, absorbing traffic oscillations.

### Controls & UI
– **Sliders/Toggles to adjust in real-time:**
– Vehicle Density / Number of Cars
– Driver Reaction Time / Fluctuation Intensity
– Target Follow Distance / Buffer Size
– Toggle Wave Damper Behavior On/Off for a specific percentage of cars (or a single controllable car)
– **Visuals:**
– Render cars smoothly on an HTML5 canvas.
– Color-code vehicles by speed (e.g., Red = Stopped/Slow, Yellow = Medium, Green = High Speed) to visually highlight traffic jam waves moving backward.
– Live charts or status indicators showing average traffic speed and velocity variance over time.

Please provide clean, modular, and well-commented code that I can run directly by opening the `.html` file in a browser.

Results (Traffic_Wave_Simulation_(IDM).html): Claude delivered a solid, working implementation on the first pass. The ring-road topology worked, vehicles adjusted their speeds based on the vehicle ahead, and a single delayed car successfully triggered a backward-propagating stop-and-go wave. The underlying engine used the well-known Intelligent Driver Model, which I had not specified in the prompt. Claude figured this out by itself.

Ironing Out Bugs

While v1 was functional, a few bugs surfaced during testing:

  1. The noise slider seems to be missing.
  2. The coefficients of the IDM should be set by sliders on the UI, so their relative magnitude can be controlled.
  3. I observe that if the follow time-gap multiplied by the speed of a car gets close to the gap between cars, the driver will want to brake to prevent it. Could this condition be revealed by changing colors somewhere? I’m aiming to reproduce something like the critical per lane traffic flow, which is found in highway dynamics? Also, give me a more intuitive explanation of the coefficients displayed.
  4. I’m not seeing any effect as I move the reaction time / fluctuation intensity slider.
  5. When I move the w_int slider to zero, cars can overtake and pass each other. This shouldn’t be since there is only one lane.

After a few brief conversational passes feeding back error logs and behavior observations, Claude corrected the issues, yielding a stable base simulation: Traffic_Wave_Simulation_(IDM)_(3).html

Phase 3: Critique, Refinement, and Feature Additions (Gemini)

Once I had a solid working base, I took Claude’s code back to Gemini for code auditing, optimization, and feature additions.

The Refinement Prompt:

I am attaching a vehicle flow simulator developed by Claude, based on this YouTube video: https://www.youtube.com/watch?v=m74zazYPwkY
As an expert programmer and traffic engineer, I'd like your critique of it. Improve it if you think you can.

Gemini reviewed the code structure, liked it in general, but had this to say:

Claude’s generated code misses a critical mechanical feature detailed in the video. The video explicitly notes that a true wave damper doesn’t just anticipate the car ahead, but adds a term to the acceleration rule to reduce the speed difference to the following car, giving them a smooth driving experience[cite: 2]. Claude’s code includes a comment claiming to “additionally bias toward the local average traffic speed,” but the actual logic only applies a basic low-pass filter (v.filteredAcc += (appliedAcc - v.filteredAcc) * smoothing) to the damper’s own acceleration without reading the following car’s state at all.

When I asked it to fix it,  the resulting code (Traffic_Wave_Simulation_(IDM)_(final).html) ran smoothly, with cleaner separation between simulation state and render loops. I changed the halo color manually to make it more discreet.

The Side-by-Side Experiment: Gemini from Scratch

As a benchmark, I also gave the original extraction prompt to Gemini directly, asking it to build the entire app from scratch in a single pass without using Claude’s intermediate base.

The Outcome: The single-pass scratch build struggled. The resulting application (gemini-code-1790354654639.html) looked a bit nicer color-wise but the simulation was less responsive to the inputs, and a number of sliders were not there. Trying to merge the straight-Gemini and the Claude code yielded something very close to the straight-Gemini code, with reduced functionality.

Takeaways on AI Model Roles

This side-by-side test highlighted how different AI models can complement each other when assigned specific roles rather than relied on end-to-end:

  1. Extraction & Architectural Planning: Gemini performed well at high-level breakdown, extracting physical principles from visual input into structured textual specs.

  2. First-Pass Code Generation: Claude excelled at translating a dense specification into working, syntactically sound interactive UI code on the first attempt. Subsequent refinements came with additional information on what the code was doing, which was added to the UI.

  3. Code Auditing & Feature Expansion: Returning to Gemini with working code created an effective review loop—finding nits and differences with the original video without breaking functionality. Trying to do the same starting from Gemini did not work nearly as well.

File Evolution Summary

Try running the final code to create the situations featured in the Lego video. It’s a lot of fun besides being informative. Incidentally, Gemini also wrote most of this article, after I gave it the following prompt. This time I turned on voice input and rambled on rather than try to be precise:

Now I would like you to help me write a blog post for my blog based on the recent experience of building this traffic wave simulator using artificial intelligence. I started asking you to look at a video on YouTube and to from that make a prompt that would be used for perhaps a different AI to make an app to replicate the effects seen on the video. Then I gave that to Claude, which produced a pretty good program the first time. I gave it a couple of passes after that, interacting with it to iron out a couple of bugs that were found, and after that, I took the code and gave it again to you, Gemini, to clean it up further, maybe to critique it and to give it some more features, and then I created a code that ran pretty well. I also gave a Gemini session the original prompt and see what it could make from scratch, and it made something that wasn’t quite functional. It had a lot of problems. So I would like to write a blog post talking, perhaps including the different prompts, which I can give to you, at different points, and referring to the different files as they kept evolving into each other.

So what do you think? Is AI going to take all of our jobs? Or maybe it’s going to allow every one of us to be the CEO. I rather think the second.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.