← Blog

How I Generated a Stack of Chinese-Language Trip Maps Without a Browser or an API Key

AI/LLM Engineering Travel

Planning a four-day Hong Kong trip, I wanted something simple: a clear map for every stop, labelled in Simplified Chinese. Not an English map with a pin dropped on it, not a wall of links. Twelve places — the hotel, the museums, Ocean Park, the Peak tram, the airport — each as its own clean screenshot I could drop into a printable booklet.

So I asked Claude Code, running in a sandboxed web session, to make them. What I expected to be a five-minute errand turned into a short tour of why "a map of Hong Kong, in Chinese" is harder than it sounds — including a coordinate system that exists specifically to make this kind of thing harder.

No browser, no API key

The obvious approach — open a maps site, switch the language to Chinese, screenshot each location — was off the table twice over. The session had no browser to drive, and the tidy static-map APIs all want a billable key. That rerouting turned out to be a feature, not a bug. Google and OpenStreetMap label Hong Kong bilingually or English-first; for genuinely Chinese labels you want a Chinese provider. The answer was AutoNavi (高德) map tiles, which render Hong Kong with Simplified-Chinese names — 海洋公园, 太平山顶, 尖沙咀 — the same names you'll see on signs and in apps once you land. The plan: pull the raw 256×256 map tiles and assemble each image by hand with Python's Pillow.

The coordinate system nobody warns you about

Here is the wrinkle that ate an hour. Chinese map providers are legally required to use GCJ-02, an obfuscated coordinate system — colloquially "Mars coordinates" — that applies a deliberate, nonlinear offset to true WGS-84 latitude and longitude. Plot a real GPS coordinate straight onto a Chinese basemap and your pin lands a few hundred metres away: in the building across the street, or out in the harbour. The offset is the point — a state-mandated speed bump against precise geographic data.

So every coordinate had to pass through the standard WGS-84 → GCJ-02 transform before any tile arithmetic: shift the centre point into Mars coordinates, fetch the tiles around that shifted point, then place the marker dead-centre so it aligns with the shifted basemap. Get it wrong and every map is subtly, confidently incorrect. Get it right and nobody notices — which is the entire job of a map.

Drawing the map

With the coordinate problem solved, the rest is image plumbing. For each location: work out which tiles cover the area, fetch and stitch them onto a 760-pixel-wide card, drop a teardrop pin at the centre, and lay a header band on top with the Chinese name, an index number, and the day of the trip. Chinese text needs a CJK-capable font; the sandbox happened to ship WenQuanYi Zen Hei, which handled it.

The step I liked best was verification. Hand-keyed coordinates are exactly the sort of thing that's plausibly-but-not-quite right, so after rendering, Claude Code read its own output images back and checked each pin against the labelled features underneath it — is the Science Museum marker actually on 香港科学馆, or one block north? A couple of pins got nudged; the Star Ferry, the Peak tram terminus, and the airport all landed on the nose. A build-it-then-look-at-it loop, still slightly novel when the thing doing the looking is the same thing that did the building.

Localization isn't translation

The maps were the easy part. The words around them were where it got human. The audience reads mainland Mandarin, and the booklet around the maps had quietly drifted into Hong Kong Cantonese register. I'd described the hotel as 地铁站上盖 — 上盖 is flawless Hong Kong property-speak for "built right on top of the station," and nearly opaque to a mainland reader. It became 就在地铁站楼上. Then 离港 → 返程, 手信 → 伴手礼, and 有得逛 — a Cantonese grammatical construction — → 能逛.

The food needed the opposite treatment. 烧味饭, 炖奶, 滑蛋 are Cantonese dish names, but they are the actual names on the actual menus, so "correcting" them would make the booklet wrong. Those kept their names and got Mandarin glosses instead — 烧味饭(即烧腊饭:叉烧、烧鹅、烧肉饭). The restaurants themselves, after a round of feedback, lost their dedicated map pages altogether: you don't navigate to dinner the way you navigate to Ocean Park, so they stayed on as text in the daily plan and dropped off the map index. None of that is translation in the dictionary sense. It's register, dialect, and knowing when a word is a regionalism to fix versus a proper noun to leave alone.

What I take from it

This lands where I keep landing: the work goes fastest on tasks that are finite and checkable. Stitching tiles, applying a known coordinate transform, confirming a pin sits on its label — each step has a right answer you can verify by looking, which echoes what I find on security sweeps and compliance tooling. The GCJ-02 detour is the genre of domain trivia that's tedious to discover and trivial to apply once known — precisely the thing worth offloading.

The judgment stayed mine: which twelve places count as "primary," that the restaurants didn't need maps, that a mainland-Mandarin reader shouldn't have to parse 上盖. The finished booklet — twelve Chinese-language maps, a day-by-day plan, and one printable PDF — came out of a sandbox with no browser and no API key. A year ago I wouldn't have guessed that was the easy version.

esc