Karakabakov
← All posts

Wildfire Lab: I built a fire simulator to see how wildfires spread

Most summers in North Macedonia, the hills burn. In Skopje you smell it before you see it, and for a week after that the evening news is a helicopter over a dry slope and a village that got lucky, or didn’t.

I’ve watched that enough times to have the obvious question and no answer to it. Why does one fire stay a black patch the size of a field while another crosses a mountain in an afternoon? People say it’s the wind, and the slope, and the heat, and how dry it’s been. I believe them. I just wanted to know how much of each.

So I built something that would let me find out. It’s called Wildfire Lab, it runs in a browser, and it’s free.

A satellite map of hills near Matka Canyon with a glowing wildfire perimeter and a smoke plume drifting south-east.

What is Wildfire Lab?

A wildfire simulator on a real map. It opens on North Macedonia, and you can pick Matka, Vodno, Galičica or Kočani from a menu, go anywhere else on Earth, or drag your own rectangle up to 40 km across. It downloads the elevation and the satellite imagery for that area, plus the buildings and roads from OpenStreetMap if you ask it to. Then you light a fire and watch.

The wind is a dial you drag. You also set temperature, humidity, rain and how dry the season has been. To fight back you can cut a firebreak, drop water, or lay a retardant line the way a plane would. The map can show the fire itself, the time it reached each spot, or where it would spread fastest if it got there. In 3D the trees catch and char, buildings go orange and then black, and the smoke drifts off downwind.

The interface is in Macedonian first, with English one click away.

How does it decide where the fire goes?

The core of it is a formula from 1972. Richard Rothermel worked out how fast a fire’s front moves through a given fuel, and fire-behaviour software still builds on his model. Cut down to its bones it says:

R = R₀ × moisture damping × (1 + wind effect + slope effect)

You can feel each part of that on a summer day. Dry grass carries fire fast and wet grass won’t carry it at all. Wind leans the flames over the fuel ahead and dries it out, and a slope does much the same, which is why fire runs uphill and creeps down. The wind effect grows faster than the wind itself, and the slope effect grows with the square of the slope. Put a hot, windy day on a steep hillside and the numbers don’t add up gently, they multiply.

Around that sit a few other well-known pieces. A fire spreads as a stretched ellipse rather than a circle, and the stronger the wind, the longer the ellipse. Dead fuel moisture comes from temperature and humidity, so a 33-degree afternoon at 15% humidity really does dry the hillside out. Forest can switch from a ground fire to a crown fire once the flames get hot enough to reach the canopy, and then everything speeds up. Burning embers also fly ahead of the front and start new fires where they land.

All of that comes from published papers, and I didn’t invent any of the fire science. My part was putting it on a real map you can poke at.

What did I get wrong first?

Quite a lot. Most of it only showed up once I tested the numbers instead of trusting what looked right on screen.

The fires were too fast when there was no wind at all. I wrote a test that lit a fire on flat grass and timed it, and the calm fire moved 50% faster than the formula said it should. Every burning neighbour was pushing on the same unburned cell and those pushes were adding up, so a cell surrounded by fire caught sooner than any single path allowed. Now each cell works out when the fire would reach it from each burning neighbour and takes the earliest. After that, a grass fire in a 25 km/h wind covered about a kilometre in half an hour, which is roughly what the equations predict.

They were also square. A grid of cells wants to spread fire in squares and diamonds, and letting the fire jump in 32 directions instead of 8 mostly fixed it. Wind-driven fires now come out as long ovals, which is what real ones look like from the air.

Embers were landing everywhere, about 390 spot fires in an hour. It looked dramatic and it was nonsense. I turned them down until a big fire on a windy day throws a handful.

At an ordinary 22 km/h breeze, 98% of the burning forest had gone up into the treetops. The threshold for a crown fire was set too low. With it raised, crowning waits for a hotter, windier day, which is when it happens in reality.

Red roofs were being read as dry grass. When it isn’t using OpenStreetMap, the app guesses what’s on the ground from the colours in the satellite image, and terracotta tiles are the same reddish brown as cured summer grass. Kočani came out as a town of 33 houses. Teaching it that the redder browns are roofs took that to 762.

Sometimes the camera ended up inside a mountain. If you interrupted the map mid-flight in 3D, it could lose track of how high the ground was and put you underneath it, and the screen went black apart from the smoke. That turned out to be a quirk in the map library, and the fix was two lines once I knew what was happening.

Real buildings were slow. Pulling every building, road and field boundary for a small town from OpenStreetMap takes 20 to 60 seconds, so I made it a switch that starts off. Without it an area loads in under a second, with estimated buildings. I’d still turn it on. Watching a fire walk up a street of real houses in 3D is when it stopped feeling like a toy to me.

Can a simulator help prevent fires?

Not directly. Wildfire Lab is a teaching tool. It isn’t calibrated against Macedonian fires, nobody who fights them has checked it, and no one should make a decision during a real fire because of it.

Prevention mostly happens in the months before a fire, though, and a lot of it comes down to people understanding what fire does. A few things I only really got after playing with it:

  • In the OpenStreetMap mode roads and rivers act as firebreaks. You can watch a flank stop dead at a road while the head of the same fire throws embers straight over it.
  • The houses that burn first usually aren’t the ones next to the fire. They’re the ones downwind, where the embers come down.
  • Rain beats nearly everything. Ten millimetres of it stops a fire that nothing else would, and the same hillside after a dry August is a different place.
  • Where you cut a firebreak matters more than how many you cut. One across the head of a fire with 35 km/h behind it gets jumped, while one ahead of a flank tends to hold.

If a teacher puts it on a projector, or someone in a village next to a pine forest tries a windy day on their own hill, I think that does some good. I also think it’s harder to throw a cigarette out of a car window once you’ve seen how fast dry grass goes in a north wind.

How long did it take to build?

An evening for the first version and a few more sessions after that. I built it with Claude Code. It wrote most of the code while I tested it, broke it and argued about the numbers. The fire maths is a few hundred lines; the rest is the map, the 3D trees, flames and smoke, and the Macedonian translation.

It’s plain JavaScript with no build step. MapLibre draws the map and three.js draws the trees, flames and smoke. The terrain, imagery, buildings and live weather all come from free and open sources.

Where is it?

At fire.karakabakov.com. Press ? once it’s open to see the keyboard shortcuts, or read how it works before you light anything.

Try the hill behind your house on a windy day, and then try it again after rain.