Skip to content

Cahid Arda Öz

Istanbul, Turkey

← Index
Blog Essays, opinions, and how-tos. / 4 min read

Bosphore 1819: Reviving a 200-Year-Old Map of Istanbul with Opus 5.5

How a map on a café wall turned into an app that reads, maps and translates all 387 labels of an 1819 French map of the Bosphorus, built with Claude Opus 5.5 subagents in an afternoon.


I built a small app called Bosphore 1819. It shows an 1819 French map of the Bosphorus, and every place name on it is listed, searchable, and given three ways: the French original as engraved, the Ottoman Turkish name in Latin and Arabic script, and the name we use today.

The code and the data are on GitHub: CahidArda/bosphore-1819.

Why

I was at a café in Istanbul. On the wall there was a huge old map of the city, and the location of the café was marked on it. I asked Claude what the map was. It turned out to be the Plan Topographique du Bosphore de Thrace ou Canal de Constantinople et de ses environs: surveyed by François Kauffer between 1776 and 1786, redrawn by Barbié du Bocage, and published in 1819 in Melling’s Voyage pittoresque de Constantinople.

The map is dense. Hundreds of villages, capes, streams, palaces and ruins, all written in French spelling of Turkish names: Roumili-Hisari, Kandlidgé, Cheïtan-Akindisi. Reading it is a small puzzle every time.

I was trying to find my neighbourhood on the map and I thought it would be fun to have an app that lists every location on the map, so you can search for a place and see where it was and what it was called. So why not build it?

Building it turned out to be the most satisfying thing I have made with AI, by far. An idea from a café wall became a finished thing in an afternoon. More on that at the end.

What the app is

  • The scan comes from the Bibliothèque nationale de France, mirrored on Wikimedia Commons, and the app shows it in a deep-zoom viewer.
  • Every label has a box on the map. Hover one and a card shows the three names, each with a literal translation.
  • You can search for place names in any of the three spellings.

The stack is Vite, React, Tailwind and shadcn/ui, with no server. First load is about 185 KB of gzipped JavaScript, most of it the viewer.

How I built it

The hard part is not the app. It is turning a 13 MB scan of engraved, letter-spaced, curved 1819 handwriting into structured data. I did it with Claude Code, and the work was split between a main agent that orchestrated and a set of Claude Opus 5.5 subagents that did the reading.

From scan to labels.jsonstep 1 / 8
scan13 MB jpeg54 tilespx gridagent 1agent 2agent 3agent 4agent 5agent 6mergededupeoverlayboxes drawnreview12 subagentslabels.json387 labels

The scan: 12,509 by 7,749 pixels from Wikimedia Commons, public domain, never copied into the repo.

Chunk the map so the reader can give coordinates

A Python script cuts the scan into 54 overlapping tiles of 1500 by 1300 pixels and renders each one at 80 percent scale with a thin red grid every 100 pixels. The grid lines are labelled with full-image coordinates, so a model looking at a tile can report a bounding box in real pixels without doing arithmetic. A second script renders any small area at up to 1.5x for text that is too fine to read.

Give the subagents one clear job

Each OCR subagent got four neighbouring tiles, a prompt with the record format, the include and skip rules, a French-to-Turkish transliteration table (ou = u, tch = ç, keui = köy) and eight verified examples. For every label it wrote a record like this:

{
  "fr": "ROUMILI-HISARI",
  "ota": { "latn": "Rumeli Hisari", "arab": "..." },
  "modern": "Rumelihisari",
  "lit": { "fr": { "en": "Fortress of Rumelia", "tr": "..." } },
  "kind": "village",
  "bbox": [5445, 4033, 5678, 4062],
  "uncertain": false
}

The one rule I pushed hardest was honesty: set uncertain: true whenever the reading, the Ottoman form or the modern identification is a guess. A flagged guess is fine. A confident wrong answer is not.

Fourteen batches ran six at a time. Each subagent read its tiles, asked for zoom renders when it needed them, and wrote one JSON file per tile. A subagent never touched anything but its own files, so they could not step on each other.

A few side jobs ran in Upstash Box sandboxes, driven from one Claude Code session through the Upstash MCP server: rendering the demo video above with ffmpeg, and editing and previewing this post before opening the pull request.

In the end

From the first script to the deployed app took one afternoon. The map had been on that café wall for years; now I can read it. Transcribing 387 labels by hand was never going to happen: not the time, and honestly not the patience. With the agents doing the reading and me doing the deciding, it was a pleasure from start to finish.

There is a lot of material like this map, on walls, in archives, in scanned books, that would be far more useful if you could search it and touch it. Turning any of it into something interactive has never been easy. It is getting easier, and I love that I get to make things like this now.

If you know Istanbul and spot a wrong identification, the data lives in plain JSON files and corrections are welcome as pull requests.