Print City Road
The Anatomy of a Beautiful Map: Lessons Learned from Auditing Our Rendering Pipeline
Back to Blog

The Anatomy of a Beautiful Map: Lessons Learned from Auditing Our Rendering Pipeline

25 May 2026
technical
7 min read

Have you ever stood in front of two side-by-side design renders, knowing one looks objectively stunning while the other feels... dry, clinical, and empty, yet you can't immediately point to why? That was my exact feeling when comparing the web renders of Print City Road with the output generated by our underlying reference tool, the Python-based maptoposter.

The Python-generated posters looked like luxury, high-end museum prints. Our TypeScript/React Canvas exports looked like a functional developer tool. In a consumer-facing indie project where aesthetics *are* the product, this isn't a small discrepancy—it is a critical failure. Today, I conducted a deep-dive, line-by-line audit of both rendering pipelines. What I discovered was a masterclass in how tiny engineering details can silently destroy visual soul.

Oversight 1: The Missing Greenery (The Data Query Omission)

The most immediate difference when looking at both maps was that the reference Python prints had rich, lush green areas (parks, grass, forests) and complex water basins, while our maps looked incredibly barren, featuring only roads and a few thin rivers.

We dug into our Overpass API fetching logic in src/lib/gl/Query.js and found a massive legacy optimization mistake. To save a few hundred kilobytes of bandwidth during our early WebGL performance tuning, a previous developer had completely stripped parks and forests from our core Overpass poster query, leaving it as:

static Poster = '(way[highway];way[natural=water];way[waterway=riverbank];)';

Because the query never fetched park or grass ways, the rendering layer never received them, rendering the corresponding theme parameters completely useless! We restored these tags and expanded the category parser in src/lib/gl/posterGenerator.ts to support dock, canal, and forest. Instantly, cities like London and Tokyo came to life with green park basins and sophisticated waterways.

Oversight 2: The Broken Vectors (The Path-Closing SVG Bug)

Next, we analyzed how water bodies and parks were drawn. In our React Canvas/SVG exporter, we batch-rendered paths in chunks of 500 ways to maintain performance. However, we found a critical vector geometry error:

ctx.beginPath();
chunk.forEach(way => {
    ctx.moveTo(start.x, start.y);
    for (let j = 1; j < way.nodes.length; j++) {
        ctx.lineTo(p.x, p.y);
    }
    // We were missing ctx.closePath()!
});
ctx.fill();

By failing to call ctx.closePath() inside the loop, the subpaths for each individual lake or forest polygon were left open. While some modern web browsers handle this gracefully on a 2D screen, it created a nightmare for our vector SVG exporter. The resulting XML was missing the Z command at the end of each sub-polygon, causing professional printing programs (like Adobe Illustrator or InDesign) to draw strange diagonal artifacts or drop the fills entirely. Adding a single ctx.closePath() call instantly resolved this, securing pristine vector print-readiness.

Oversight 3: Typographic Soul (Spaced Latin Typography)

Perhaps the most profound aesthetic difference lay in the main city title. The reference Python tool produced an incredibly clean, luxury editorial feel, while ours looked crowded and generic. The secret was a simple yet brilliant typographic trick in the Python codebase:

if is_latin_script(display_city):
    spaced_city = "  ".join(list(display_city.upper()))

Instead of just drawing the string "PARIS", it physically split the characters and joined them with double spaces, rendering "P A R I S". This generous letter spacing (often called tracking) is a standard hallmark of minimalist Swiss design.

We ported this heuristic directly into our posterGenerator.ts, building a lightweight character-code checker (isLatinScript) that separates Latin letters with double spaces, while keeping CJK, Thai, and Arabic script structures intact. We also calibrated the dynamic font sizing to scale down based on the original un-spaced length, preventing long city names from spilling off the poster edge.

The Takeaway: Aesthetics are Engineering Requirements

This audit reminded me of a vital product lesson: **Aesthetics are not soft "nice-to-haves" that you sprinkle on top of a working tool—they are hard technical requirements.** An engineering pipeline that compiles cleanly but produces a visually unappealing consumer product is still broken.

By taking a step back, humbling ourselves, and running a transparent comparison against our source of inspiration, we closed the gap. Our generated posters now have the same lush, rich geographical depth and luxury minimalist typography as the finest Python scripts, all running seamlessly in a client-side Next.js web application. The update is live—happy creating!

Tags#Aesthetics#Canvas API#WebGL#OpenStreetMap#Build in Public