I Built an Open-World Copenhagen With Claude Code
- Grand Tour Copenhagen is the real Copenhagen in your browser. Drive, bike or walk today's city, then press Y for 1760.
- It runs on Lasse Saari's open-source worldhood engine, with houses from Københavns Kommune's open 3D city model.
- I built it with Claude Code in about a week, over 300 commits from the data scripts to the trailer.
The short version
Grand Tour Copenhagen is the real Copenhagen in a browser tab. You drive, bike or walk around today's city, and when you press Y you're standing on the same spot in 1760.
You can play it at gtcopenhagen.com. It works on a phone, but a laptop is better.
It's built on worldhood, an open-source city engine made by Lasse Saari. He did Helsinki first. I forked his engine on 12 October and added Copenhagen.
I built it with Claude Code, and I used it at every step: the game code, the data scripts, the 3D models, the checks and the trailer. That came to over 300 commits in about a week. When I write "we" below, that's me and Claude Code.
This is the long version, with screenshots of what broke.
How it started
It started with a LinkedIn post. Lasse shared GTA Helsinki, a version of Helsinki you could drive around in your browser. I live in Copenhagen, so on the morning of 12 October I started on one for here, with a few twists so it wouldn't be a copy.
Half an hour later I had a three.js game called Grand Theft Ladcykel (a ladcykel is a Danish cargo bike). It was Copenhagen built from scratch on OpenStreetMap, and by 10:10 it was live on my Cloudflare account. The main twist was a switch that takes you back to historical Copenhagen, with old vehicles and buildings that aren't there anymore.
By the afternoon it had about 8,800 buildings, bikes, cargo bikes, cars, GoBoats and police that came after you. It also had six sagas from Danish folklore, a morning paper written from what you did the day before, and title art I made with OpenAI.
It still felt clunky. The streets were empty and some of the buildings looked bad.
Lasse's version looked a lot more real and full. His engine, worldhood, is MIT-licensed, built so a new city can be added with a couple of commands, and much smoother to drive. So that afternoon I tried Copenhagen in it.
I forked it at 16:44 and brought my extras across: the 1760 switch, the sagas, the morning paper, the cargo bike, delivery jobs and the GPS line.
The name came later. I wanted Copenhagen in it, but GTA is a Take-Two trademark, so it became Grand Tour Copenhagen. I also kept the fork's own look instead of copying other city games.
The setup
I worked with Claude Code in a cloud session: a Linux machine with the repo checked out, a dev server and a headless browser for screenshots.
The code lives on GitHub. Every push to the main branch starts a build on Cloudflare, and about two and a half minutes later the new version is live. The game is only static files (HTML, JavaScript, 3D models and city data), so hosting it costs nothing.
We kept three copies of the code side by side, called git worktrees. A long job could run in one while a quick fix went out from another.
A normal day went like this. I tested the latest build and decided what to fix or add next. Then I built it with Claude Code, checked the result and pushed it, and tested again.
When a check failed, the change went back for another round before it was pushed.
At night I set it up to keep going without me, working through a task list on its own.
The first run lasted 8 hours and the next one 14. After that it became one continuous session that checked in on itself on a schedule and pushed every batch that passed its checks. On the last two days I ran a second session alongside it for the trailer and the crowds.
Today's Copenhagen, from open data
Almost nothing in the city is placed by hand. Scripts build it from open data, and the game reads the result. The map is a circle 4.4 km across, centred on the old town.
| What you see | Where it comes from | How many |
|---|---|---|
| Houses | Københavns Kommune's 3D city model from 2013, plus OpenStreetMap for newer buildings | 20,744 |
| Street trees | The city's street-tree register | About 21,000 in the register |
| Lamps, signs, poles, bike racks, benches, bins | The city's registers, plus objects Mapillary spotted in street photos | 66,944 in the data, before duplicates are dropped |
| Bicycle symbols on the cycle tracks | Cycle tracks in OpenStreetMap, one symbol every 40 m | 6,690 |
| Parked cars | A script that looks for free kerb space | 3,540 |
| Boat moorings | A script that walks every quay looking for open water | 1,261 spots |
Streets, paths, water and parks come from OpenStreetMap. The public servers kept timing out, so we downloaded the whole city as one file (a BBBike extract) and built from that.
Helsinki has a textured 3D model of the whole city. Copenhagen doesn't have one like it, so I went looking and found the municipality's model from 2013.
Each city block in it is one big mesh. A script cuts it into separate houses along the OpenStreetMap outlines, roof by roof and wall by wall. The houses keep the heights the city measured.
What you see and what you bump into are two different things. The car collides with building footprints, not with the 3D model, so the two have to match. For a while they didn't, and you could drive straight through the rows of houses in Nyboder.
OpenStreetMap often draws pavements as lines, or not at all. So a script paves everything within 5 m of a road that isn't a house or water. That added 3.4 km² of pavement.
Nyhavn got special treatment. We went through street-level photos on Mapillary and wrote down the colour of each facade along the north quay, 30 houses in order.
Copenhagen in 1760
1760 isn't a separate map. It's today's map run through a script that takes the modern city away and puts the old one back, using the city's own register of building years.
Inside the old walls the streets haven't moved much since then. So the street plan and the plots stay, and the modern blocks get restyled as period houses.
Outside the walls, a house only stays if the city's SAVE register dates it to 1760 or earlier. The register lists 31,018 buildings. Everything else becomes open fields, with the old country roads leading out of the city gates.
The western and northern ramparts are rebuilt as earthworks with bastions and a moat, and a windmill stands on each of the 12 bastions. You can still trace them today. Vester, Nørre and Øster Voldgade run along the inside, and the lakes in Ørstedsparken, Botanisk Have and Østre Anlæg are what's left of the moat.
A few landmarks that are gone today were built by hand: the old Gothic Vor Frue Kirke and the spire of Nikolaj Kirke. The Marble Church is a building site, because in 1760 it was only half built.
Taking things away was harder than it sounds. Modern footprints with no house drawn on them were still solid. For a while the Opera, BLOX, the Black Diamond and 140 other buildings were invisible walls in the middle of open squares.
There are no trams or buses. Your car becomes a coach pulled by two horses, with a coachman in a tricorne up front. There are lanterns instead of street lamps, market stalls, pigs and hens, barrels and crates on the quays and tall ships in the harbour.
The men in 1760 wear 18th-century costumes I picked out, and the player gets a blue coat. Half the squares have a night watchman and most have a woman spinning at her distaff. The background music is generated folk tunes, played on a cittern.
Making it feel like Copenhagen
Empty cans lie by about a quarter of the benches, a third of the bins and nearly half the bus shelters, plus two at every hot-dog stand. Each one is worth its 1 kr deposit, like the real thing. A can you pick up comes back five minutes later, and you get a title at 10, 50, 150 and 400 cans.
The can itself is an artist's model, repainted as a lemon-lime soda with no name or logo.
There are five hot-dog stands: two on Rådhuspladsen, and one each on Kongens Nytorv, Amagertorv and at Torvehallerne.
The harbour bath at Islands Brygge has its decks, its diving tower and people swimming. Geese graze in groups of three to seven in the big parks and waddle off when you get within 5 m. Some walkers have a dog on a lead, and a third of the empty bike racks have a cargo bike parked at them.
Hidden nisser, the house gnomes of Danish folklore, sit around the city for you to find. Their boss, Nissefar, lives in Kongens Have and wants porridge.
There are six sagas, short stories from Danish history and folklore. Andersen's Three Homes and Gefion's Plough play today, and Porridge for the Nisser and Holger Danske's Map run in both eras.
The other two only exist in 1760: The King's Eye, which a ghost gives you, and Fire Watch, a night shift with the watchman.
The city follows the calendar. From 10 October to 2 November there are carved pumpkins on the doorsteps and café tables and orange lights over Nyhavn. From 20 November to 6 January it's Christmas trees on the main squares, lights over the shopping streets and falling snow.
The car has a radio with five stations. They play music that's in the public domain or under open licences, streamed from the Internet Archive and Wikimedia Commons.
From stick figures to people
The people started as simple figures drawn in code. Up close they were blocky stick figures, and in 1760 some of them also floated above the ground.
So we went looking for character models. They started as free Quaternius characters, and later a Ready Player Me avatar I found joined them. There are 29 in the game now, from a guy in a hoodie to sailors, a shipboy and a woman in a Victorian dress.
Each family of models shares one skeleton, so a few sets of walk, run and idle animations move the whole crowd. Only the ten people nearest the camera (five on a phone) and the player are fully animated. Everyone else out to 140 m uses the same models baked into 12 animation frames, so 80 people cost about a dozen draw calls.
For 1760, I dressed that avatar in the 18th-century costumes I'd found. They have long coats in red, blue, brown and green, a waistcoat, breeches, stockings and a cravat, plus powdered hair and a tricorne. The coachman is the same man, sitting down.
H.C. Andersen is an easter egg I added on day three. He stands outside Nyhavn 20, and yes, he can chase you.
He got his own build, with a black coat, a white cravat and a top hat. In the first preview, his top hat came out as a flat disc sticking out sideways. The 3D library builds cylinders lying down, and nobody had stood it up.
His coat was jagged until the model got more detail. He also stood with his feet wide apart, because the standing animation was made for a different body. And at first he stood inside his own front door instead of on the pavement outside it.
The failures, with screenshots
Most of the week went into fixing things that looked wrong. A few were funny. Here are the best ones, in order.
Flat walls, windows on the inside
The municipality's model has no textures, so every wall started out as one flat colour. About 45% of the model is also built inside-out, so on those houses the windows sat inside the walls until we flipped them.
A box for a coach
That first coach was a box drawn in code. Next we built one in Blender, and in the end it became a 19th-century coach and a horse model I found, with a coachman on top.
Poles in the lanes, and a forest of signs
Some of the street furniture comes from Mapillary, which spots objects in street photos. It sees the same sign in many photos, so we got forests of signs, wooden utility poles and doubled traffic lights. Cleaning up the duplicates removed 7,483 of 17,633 sign posts, 1,488 poles and 606 traffic-light heads.
The poles standing in the lanes were a separate bug, fixed on the first morning.
The car in the canal at Nyhavn
The ground near the water had sunk by up to 2 m, so parts of the quay ended up under the water. It took until 18 October to fix it properly.
A coach on its side
The code that levels the ground also lifted single points by up to 2 m, which put spikes into squares like Højbro Plads.
Driving on water in 1760
In 1760, 79 of the 90 bridges dropped you into the water. Today's city had the same problem on 120 of 261.
The Little Mermaid, airborne
By that afternoon she was back down on her rock.
Knippelsbro from above
Paving that lies over water gets thrown away, so the canals don't get paved over. That rule also caught the bridge decks, so the deck showed through in patches. Now the paving stays wherever there's a bridge deck under it.
The rest of the list
| Date | What it looked like | Why |
|---|---|---|
| 13 Oct | Boats floating 4 m above Nyhavn, three-masters in the Lakes | Boats ignored the water level and the kind of water |
| 13 Oct | Granite kerbs lying across roads | Kerbs were only checked at the middle of each edge |
| 13 Oct | No street surfaces on the live site | Commas in file names sent Cloudflare's file server into a loop |
| 13 to 18 Oct | Police cars, bridge decks, walkers and two statues went missing | Five times, a // comment in a one-line statement switched off the rest of the line |
| 14 Oct | The live game failed to start for 10 to 15 minutes after a push at 01:00 | The harbour bath asked where its diving tower was before the tower existed |
| 15 Oct | Flickering grey and red walls | About 400 buildings are in the model twice |
| 17 Oct | Hollow buildings with walls hanging in the air | Their lower floors were never modelled. Walls now reach the ground on 5,302 buildings today and 1,511 in 1760 |
| 18 Oct | Grey stripes on the coach wheels | The texture was read upside down |
| 18 Oct | Pumpkins in every trailer shot | Decorations follow the date, and it was October |
| 19 Oct | Nisser standing on road crossings and in the water | Their spots didn't check for roads and water |
| 19 Oct | A wall of trees on Rådhuspladsen | The tree register lists some trees twice, so 77 trees stood within 40 m. Now it's 29 |
| 19 Oct | Bricks in the road | Leftover kerb pieces from small scraps of pavement |
| 19 Oct | Black squares all over 1760 | One broken pixel (a NaN, "not a number") spread through the blur effects |
| 19 Oct | After a crash, the driver got out of a car that was still rolling, and his door stayed standing in the road | He got out before the car had stopped |
How we checked the work
I couldn't play every build myself, and Claude Code can't see the game the way I do. So a lot of the work was building checks.
The cloud machine has 2 CPUs, 8 GB of memory and no graphics card. It draws the game in software inside a headless browser, and starting it once took 5 to 8 minutes. It's slow, but it meant we could take screenshots from any camera position.
For the trailer, a script holds every shot near its start, middle and end. It puts the frames side by side on one image, a contact sheet. One sheet covers every shot in the trailer, so a broken one jumps out.
Some bugs are easier to find with numbers than with pictures. To find floating people, a script fires a ray straight down from every walker and reports anyone whose feet don't touch the ground.
Other checks go over the whole city. Rays from inside every house look for walls you can see through. Another check looks for houses you can drive through and walls you hit but can't see, and another for bridge decks with no ground under them.
One check looks for steps and spikes in the ground under streets and pavements. Before the fix it found 609 spots under streets where the ground jumped by more than a metre. After the fix, 151.
There are about 750 automated tests, and they had to pass before every push, along with a smoke test that starts the game. Sub-agents also reviewed the code 11 times.
We hit every limit the machine had. Two headless browsers at once ran it out of memory, and the browser got killed.
The dev server died after two hours and had to be restarted between runs. Once the whole machine restarted in the middle of the night, and the session picked up where it had stopped.
None of this replaces playing it. I still found things the checks missed, like the striped wheels on the coach.
Shipping it
On 17 October I heard someone had already made Oslo, and I didn't want anyone to beat me to Copenhagen.
That's when I pushed for launch: the new name and a cinematic mode for the trailer. The download had already got lighter overnight, with the city data cut from 10.2 MB to 3.1 MB.
For one night, every commit on GitHub had a red cross from Cloudflare next to it. It looked like the site was broken, but it wasn't. We were also pushing a second branch, and Cloudflare built it as a preview with a command that refused to run without a setting we didn't have.
GitHub only showed that red check, which hid the green production deploy. I pulled the build log from Cloudflare, and with it the fix was one empty block in the config.
On 19 October I bought gtcopenhagen.com from Cloudflare's own registrar. It costs $10.46 a year, with no markup and the same price on renewal. Attaching it to the game took two clicks, and HTTPS came with it.
Hosting is free, so the domain is the only bill for the game itself.
The cloud machine couldn't record video without a graphics card. So in cinematic mode the game drives itself through the shots, and I recorded my screen on my Mac.
Add ?cinematic to the address and it plays the scripted shots. There's the car through the city, slow orbits around landmarks, Halloween at Nyhavn and the Christmas tree on Kongens Nytorv. In 1760 most of the same shots run with the coach.
The trailer needed its own debugging. The car snapped sideways at junctions, shots started before the character models had loaded, and sometimes the car wasn't drawn where the camera was looking.
What I learned, and what's next
Claude Code made me fast at every step. What it didn't replace was deciding what to build, what good looks like, and when something wasn't there yet. That still takes someone who knows what Copenhagen is supposed to look like.
I stopped trusting "fixed" on its own. Every change had to come with a screenshot, a number or a test before I believed it. The checks caught far more than I would have by playing alone.
Without Lasse's engine I'd still be on version one. Without the municipality's 3D model and registers, there would be no city to drive around in.
Next is making it right street by street. If you live in Copenhagen, find your street and tell me what's wrong or missing. I'm also looking for more characters, like people in winter coats for December.
Credits
Of the 96 3D models in the game, about 50 started as models I downloaded, mostly from Sketchfab. We built 31 in Blender, and 14 are free Quaternius characters and animations from the first version.
- Engine: worldhood by Lasse Saari and contributors, MIT licence.
- Map data: © OpenStreetMap contributors, ODbL.
- City data: Københavns Kommune, CC BY 4.0: the 3D city model (2013), street trees, street lights, bike racks, bollards, wires and masts, and the SAVE register of building years.
- Street-level photos and detected street furniture: Mapillary (photos CC BY-SA 4.0, map features under Mapillary's terms).
- Elevation: Mapterhorn terrain tiles.
- Radio: music in the public domain or under CC0, CC BY and CC BY-SA, from the Internet Archive and Wikimedia Commons.
- People (CC BY 4.0 unless noted): characters by Quaternius (CC0); "Cool Man" by ardhanaputra and "Avatar Full body - Ready Player Me - pmariano" by Patricio Mariano (Ready Player Me avatars, non-commercial use under Ready Player Me's terms); "Woman Dress 2" by Ali Şahan Yalçın; "Victorian Woman dress 3d model" by abauerenator; the merchant's wife and the spinner by the Department of Historical Information Science, MSU; "Royal Navy Shipboy" by JanPohl; "Pirate Crew - 3D Character Pack" by Itom; the night watchman by augustusburg_ger; the 18th-century coats from costumes by the IVSPU Department of clothes pattern design (Victor Kuzmichev, Aleksei Moskvin, Mariia Moskvina) and by Aleksei Moskvin.
- Animals (CC BY 4.0): "Goose Low Poly" by Atlas, "dog" by neighbor, "lowpoly pig" by fabiotambone, "Chicken" by pooiloui2 and "Armored Horse" by naminoff.
- Vehicles and boats (CC BY 4.0): "19th Century Carriage" by Digital Goblin; "Horse Drawn Carriage 16" and "9" and "Merchant Schooner 3" by agt14032013; "Day 249: Babboe cargo bike" by alban; the frigate Svjatoi Nikolai and the schooner yacht Amphion by Museovirasto (Finnish Heritage Agency); "Weathered 18th Century Galleon" by Galaxy Abundant; HDMS Gorm by martyn169.
- Props and statues (CC BY 4.0 unless noted): the Frederik V statue by alexabhisak; the H.C. Andersen statue by rigsters; "Giant Hot Dog Stand" by Ariel Stull; "City Trash Can" by _Tempus_; "Cans!" by Tiago Oliveira; pumpkins by monsieurmo, Nick Kotik and Charlie Tinley; "Pirate Cannon" by maxwellmccurry; "Barrels" by RipeR; "Crate" by SomeKevin; "Elizabeth's Food Stand" by bpcrews; "Gnome (Female) (Pig Tails)" by David Wigforss (CC BY-NC 4.0, non-commercial use).
- Trees: "Realistic Tree" by Daniel (danielpetrov) and "Tree GN" by TechArtBGN (CC BY 4.0), plus procedural trees from EZ-Tree by Daniel Greenheck (MIT).
The game's sources panel lists every model and dataset, with where it came from.
NowGTM at Claimlane
Latest postLatest from the blog