How to Fix Slow Roads Lag and Low FPS
Most advice about Slow Roads performance is guesswork. This is not: everything below comes from reading the settings code in the build that runs on this site, so the fixes are ordered by what the engine actually spends its time on.
Measure first, then change one thing
The build ships with a stats.js frame counter, created at startup and then hidden. It is bound to F3, under the internal name Debug. Press it while driving for the familiar small panel with a live frame rate and graph. Some browsers also use F3 for "find next", so you may get a find bar too; Esc dismisses that and the counter stays.
The same key brings up a second readout the counter does not show: the current version and seed, the live draw call count, and counters for the heightmap cache, roadside objects and far cells. Draw calls are the useful one. They are how many separate batches the renderer submits per frame, and they climb with view distance and environment detail rather than with render scale — so if draw calls are high and the frame rate is low, the fix is in the two distance settings below, not in the resolution. F4 adds the camera's world position on top, which is only of interest if you are hunting for a particular spot.
The number matters because two different problems feel alike. A steady 25 fps is a load problem: the GPU is drawing more than it can. Irregular hitching, where the picture freezes briefly then catches up, is terrain generation on the main thread. Load responds to everything below; hitching responds mainly to view distance, because that governs how much world gets built.
Change one setting at a time and drive for ten seconds before judging it. The controls reference lists every binding if you need it.
Why this game is heavier than it looks
Nothing here is pre-baked. Road, terrain, tree placement and roadside furniture are all produced as you drive by procedural generation from a single seed. The renderer is three.js drawing through WebGL, and the whole simulation shares one main thread with the React interface.
So there are two costs: pixels shaded per frame, and terrain built and submitted as you move. The settings hit those two unevenly, which is why the order below is what it is.
1. Render scale — by far the biggest single win
Render scale offers 0.5, 0.75, 1.0 (the default) and 1.5. In the code it is a plain multiplier on the drawing buffer — the renderer is sized at width times scale by height times scale — so because it multiplies both axes, the pixel count moves with the square of the number.
| 0.5 | 960 × 540 on a 1920 × 1080 window — 518,400 pixels, 75% fewer than default |
|---|---|
| 0.75 | 1440 × 810 — 1,166,400 pixels, about 44% fewer than default |
| 1.0 | 1920 × 1080 — 2,073,600 pixels, the default |
| 1.5 | 2880 × 1620 — 4,665,600 pixels, 2.25× the default |
That 44% is the number worth remembering. One click from 1.0 to 0.75 removes nearly half the shading work, and every per-pixel effect gets cheaper in proportion. No other setting here comes close. It is also the only one that applies instantly: it calls the renderer's resize path and nothing else, where view distance and environment detail throw the generated world away and rebuild it.
Why 0.75 looks fine on a laptop and worse on a desktop monitor
The build clamps its pixel ratio with setPixelRatio(Math.min(1, window.devicePixelRatio)). On a high-DPI display — a Retina MacBook, a 4K laptop panel, Windows at 150% scaling — that clamp means even at render scale 1.0 the game is already drawing below the native pixel grid and the display is already scaling up. Going to 0.75 only changes the ratio of an interpolation that was happening anyway, so the softness is far less visible than the numbers suggest.
On an ordinary 1× monitor there is no cushion. You had one drawn pixel per screen pixel and now you do not, so edges and distant road markings visibly soften. Usually still the right trade against 20 fps, but that is where you will see it.
If you are comfortably above 60 fps, 1.5 is a good use of the headroom. It is supersampling: the game draws at 2.25× and the browser scales down, which kills edge crawl on fences and power lines better than the antialiasing option does.
2. View distance before environment detail
These two look like a matched pair in the menu. They are not. Each view distance level is a table of horizon values in the code; the two that matter are farSize, the side length of the far terrain grid maintained around you, and viewDist, which becomes the camera's far clipping plane.
| low | far grid 200, camera far plane 200, road generated 40 ahead / 5 behind |
|---|---|
| med | far grid 400, camera far plane 800, road generated 90 ahead / 10 behind |
| high | far grid 700, camera far plane 1400, road generated 180 ahead / 16 behind (default) |
| ultra | far grid 1000, camera far plane 2000, road generated 250 ahead / 25 behind |
Terrain is a surface, so cost follows the square of that grid size. Against the high default, ultra maintains roughly twice the terrain area and med about a third of it — and all of it has to be generated, meshed, culled and submitted every frame, with the generation sharing a thread with your steering input. Stepping high down to med is the most effective fix for hitching there is.
Environment detail does something different. It sets the mesh resolution of the ground near the car (10 at low, 24 at ultra) and switches off the things you are close enough to see. At low, grass and bushes are never added to the scene, tree foliage stops rendering, roadside rubble is skipped and the far valley walls are dropped. It also quietly controls shadows. The shadow map is sized at 512 pixels times the level index plus one, so low gets a 512-pixel map, med 1024, high 1536 and ultra 2048. Search the menu for a shadow quality option and you will not find one: there is no such setting in this build, and this is the control that stands in for it.
So environment detail buys back less per click, and it takes away the near-field things that make the game look like itself. Drop view distance first; touch detail only if med was not enough.
One cliff to know about: if either of these is set to low, the code hides the sky dome entirely and you get a flat background colour. It is cheap, and it looks it — a good reason to prefer med on both over low on one.
3. Hardware acceleration in the browser
This sits lower on the list only because it is either fine or catastrophically broken, with nothing in between. If the game runs in single digits and everything stutters — menu, camera, splash screen — while a lower render scale changes nothing at all, you are rendering in software. The browser has fallen back to a CPU rasteriser and no in-game setting rescues that.
Open chrome://gpu or edge://gpu and read the Graphics Feature Status block: WebGL and WebGL2 should say "Hardware accelerated", not "Software only". The toggle is in Chrome under Settings → System → "Use graphics acceleration when available", in Edge under Settings → System and performance, and in Firefox under Settings → General → Performance. Restart the browser; it is read at process start.
On a school or work laptop the toggle may be greyed out, because acceleration can be disabled by administrator policy. You cannot fix that from inside the browser, and a WebGL game is not playable without it — the guide to locked-down networks covers what is and is not worth trying.
4. Antialiasing
Antialiasing exists in this build as a stored config value, config-antialias, default on — but there is no switch for it in the settings menu. It is handed to the WebGL context when the renderer is constructed and nothing listens for changes, so it is a startup option, not a live toggle.
You can still set it: on the game page, open the browser console, run localStorage.setItem('config-antialias', 'false') and reload. The loader runs each stored config value through JSON.parse, so the string arrives as a real boolean and the context is built without multisampling.
Expect a modest gain, largest on integrated graphics and at higher render scales, since multisampling cost scales with buffer size. The corollary matters more: if you are already at render scale 0.5, leave it on. At that size it costs little and it is the only thing keeping the upscaled edges from looking ragged.
5. Other tabs, and why they hurt
You have one GPU, and every WebGL canvas and accelerated video in every window queues onto it. A background YouTube tab is not idle; it is decoding and compositing. The game does ask for the fast path — the renderer is created with powerPreference: "high-performance", a request for the discrete card on a dual-GPU laptop — but that is a hint, and browser power settings or a vendor control panel can hand you the integrated GPU anyway.
Closing tabs genuinely helps here, in a way that closing unrelated applications usually does not. Leave pause when inactive on too: the game then stops when the window loses focus rather than competing with whatever you switched to.
6. Battery and power settings
An unplugged laptop is a different machine. The OS and the browser both throttle on battery, and on many machines the GPU clocks down far enough to halve frame rates by itself. If it was smooth yesterday and is not today, check the charger before you change a setting. Worth a look in the same pass: Windows power mode set to Best performance, your browser's efficiency or battery-saver mode, and the resolution of any second monitor you dragged the window onto — the game renders at whatever size the window happens to be.
What will not help
Plenty of standard advice does nothing here, and it is worth saying why.
- Clearing your cache. It re-downloads about 16 MB of assets and changes nothing about frame rate. There is no service worker in this build, so there is no stale worker to purge either.
- Anything about WebAssembly or threads. There is no
.wasmhere and noSharedArrayBuffer, so cross-origin isolation headers and "enable multithreading" flags are irrelevant. The simulation is plain JavaScript on one thread. - Clearing localStorage. It holds your seed, settings and records, a few hundred bytes. Wiping it resets your progress and buys nothing: the localStorage API is not in the render path.
- Downloading an offline version. Sites offering a "Slow Roads .exe" are not shipping this game. It is a browser build and performs the same wherever it is hosted.
- Switching to a phone. This build refuses mobile devices because it needs a hardware keyboard, and the override adds no touch controls — the mobile guide covers what it does and does not do.
Be realistic about the ceiling. Continuously generated 3D terrain is demanding to run in a browser tab, and some hardware will not hold 60 fps at any combination of settings. On a low-power integrated GPU, a stable 30 at render scale 0.75 and med view distance is a good outcome. The game is pleasant at a steady 30 and unpleasant at an unstable 45.
A starting recipe
| Struggling badly | render scale 0.5, view distance med, environment detail med, other tabs closed |
|---|---|
| Playable but choppy | render scale 0.75, view distance med, environment detail high |
| Comfortable, want it prettier | render scale 1.0 or 1.5, view distance high or ultra, environment detail ultra |
Settings persist in localStorage, so this is a once-per-browser job. Then go and drive.
One honest note about this build
What runs here is version 1.0.1, the public web build captured around November 2022, made by anslo. The settings above are the settings that exist in this version. The official game at slowroads.io has moved on considerably since — different options, different performance behaviour, new content — so if a guide elsewhere names a graphics setting you cannot find here, that is usually why. Try the current version too; it is the same author's work.
Once the frame rate is sorted, the rest of the guides here cover what to do with it: seeds, the weather cycle, and how the three vehicles differ.
Play Slow Roads → Free in your browser. Desktop or laptop with a keyboard.