Two clocks
Vehicles in BuildCity live on two different clocks. The physics clock advances the simulation in ticks of 50 to 120 milliseconds, depending on how busy the browser is: each tick, every vehicle looks at the road ahead, picks a speed, and moves along its path. The render clock is the browser's own, typically 60 frames per second, and it draws whatever positions the vehicles currently have. When those clocks disagree, which is always, a car that moved once per physics tick but was drawn several times in between appears to sit still and then jump. Players described it as stuttering or teleporting, and they were right.
This article explains the September 2026 fix for that, the measurements behind it, and why, after all of that, we still have not turned on traffic lights.
Interpolating between ticks
The fix is conceptually simple: keep each vehicle's previous and current physics positions, and on every render frame draw it at a point between them based on how much time has passed since the last tick. Straight segments used to copy the physics position directly, and curves snapped to the new position whenever the difference was large; both of those behaviors were removed. Instanced vehicles, which share one mesh for many cars, are interpolated too, with "do not render this one" kept separate from "this one is drawn by the instance pool." Off-screen vehicles use the same curve math and keep their heading, so a car that comes back into view is already facing the right way.
A second, less visible bug was a time leak. Ticks longer than 100 milliseconds were being truncated to 100, so a browser that slowed down also quietly slowed the whole city. Ticks are now processed up to 150 milliseconds, and visible and mission vehicles move in sub-steps of at most 50 milliseconds inside a long tick. We deliberately do not try to catch up the entire time a tab was suspended; a city that was in the background for five minutes resumes rather than fast-forwards.
Heading is now calculated from physics positions and only the visual rotation is interpolated at render time, and the lookahead check that keeps vehicles from driving into each other runs on a time budget instead of a frame count: about ten times a second for vehicles on screen and about four times a second for mission vehicles off screen, plus whenever a route changes.
The numbers
A test harness loads the real vehicle code with the world and renderer stubbed out, so it can count exactly what happens frame by frame. It is not a GPU benchmark and does not cover every possible road layout, but it isolates the motion logic cleanly.
| Scenario | Before | After |
|---|---|---|
| 20 Hz physics, 60 Hz render: frames where a moving car did not move | 112 of 167 | 0 of 167 |
| Same scenario: largest single-frame jump | 0.06 tiles | about 0.02 tiles |
| 20 ticks of 120 ms, car at 1.2 tiles per second: distance covered | 2.40 tiles | 2.88 tiles |
| Spatial cells still marked occupied after one car crossed 100 of them | 100 | 1, and 0 after removal |
We also measured the top-ranked public city in a real browser on a desktop GPU. After a 45-second warm-up, a 10-second window averaged 41 frames per second with a minimum of 32, around 1,143 draw calls, about 18.5 million triangles, and 40 vehicles on the road, with no page errors. That is one high-end sample from one camera angle, so we do not quote it as the game's performance; we quote it as the reason the next section is cautious. Even on good hardware, a large city does not have a lot of headroom to spend.
Deadlocks and double arrivals
Two smaller fixes rode along. Vehicles that were removed by the deadlock breaker could be re-registered in the spatial grid by a late position update and haunt a cell forever; that path is closed. And when a vehicle's arrival callback replaced its route or ended it, the remaining sub-steps of that tick now stop, which prevents logistics and school-bus handovers from being processed twice. Neither changed anything on the server; vehicle motion is entirely client-side and the save format is untouched.
Why traffic lights are still off
There is traffic light code in the client. It has been there for a long time, nobody calls it, and turning it on would be the wrong move for three reasons we worked through in the same review.
First, the existing signal mesh builds four independent meshes per direction per intersection. A city with a hundred four-lane intersections would add up to around 1,600 draw calls if they were all visible, on top of the 1,143 measured above. Signals have to be a handful of instanced meshes with an emissive material, updated only when a color changes and skipped at distance. Second, the old intersection detector counts four-lane grid neighbors, which also matches a straight stretch of four-lane road, so straight roads would sprout lights. Intersections need to be identified from actual entry and exit directions when roads change. Third, the signals were never connected to vehicle behavior: amber was a timer with no meaning, and crossing traffic was invisible to the lookahead check.
The design we would build instead shares a single simulation clock across all intersections with a per-intersection phase offset, so there are no per-intersection timers and nothing to ask the server. Each vehicle caches its next stop line and signal when its route segment changes, so the per-tick cost is one lookup and one distance check per vehicle rather than a comparison against every intersection. Protected left turns, an all-red clearance phase, not entering a blocked exit, and exempting signal waits from the deadlock breaker are all on the list, as is making off-screen vehicles obey signals, because the lightweight off-screen path currently skips lookahead entirely.
What you should notice
- Cars move smoothly between physics updates instead of pausing and jumping, including on curves and when turning from a two-lane onto a four-lane road.
- A city in a slow browser tab no longer runs its traffic in slow motion.
- Vehicles that leave and re-enter the view arrive facing the right way.
- Long sessions no longer accumulate phantom obstacles that make vehicles hesitate at empty cells.
If you want the practical side, the road layout guide covers how corridor design keeps vehicles flowing without any signals at all, and the low-end PC article explains the rendering profiles that decide how many of those vehicles your machine will see.