Star ๅކๅฒ่ถ‹ๅŠฟ
ๆ•ฐๆฎๆฅๆบ: GitHub API ยท ็”Ÿๆˆ่‡ช Stargazers.cn
README.md

MapPoster Online

MapPoster Online

Turn the cities you love into stunning designs

English | ็ฎ€ไฝ“ไธญๆ–‡


Project Description

A browser-based upgrade to maptoposter (Python CLI) โ€” no installation needed, just open and go

React TypeScript Tailwind CSS Bun Rust License

Gallery

Asia

China - BeijingJapan - TokyoSouth Korea - SeoulChina - Hong Kong
BeijingTokyoSeoulHong Kong
SingaporeMalaysia - Kuala LumpurThailand - BangkokIndia - New Delhi
SingaporeKuala LumpurBangkokNew Delhi

Europe

Switzerland - ZurichNorway - OsloSweden - StockholmDenmark - Copenhagen
ZurichOsloStockholmCopenhagen
Austria - ViennaGermany - BerlinUnited Kingdom - LondonFrance - Paris
ViennaBerlinLondonParis
Italy - RomeRussia - MoscowTurkey - IstanbulNetherlands - Amsterdam
RomeMoscowIstanbulAmsterdam

Americas, Africa & Oceania

USA - New YorkCanada - OttawaBrazil - Sรฃo PauloMexico - Mexico City
New YorkOttawaSao PauloMexico City
Argentina - Buenos AiresAustralia - MelbourneSouth Africa - Cape TownChile - Santiago
Buenos AiresMelbourneCape TownSantiago

Features

  • ๐Ÿš€ Zero installation โ€” Runs entirely in the browser. Open the site, pick a city, and download your poster
  • โšก Rust/WASM rendering engine โ€” High-performance map rendering compiled from Rust to WebAssembly (powered by tiny-skia)
  • ๐Ÿ‘๏ธ Live preview โ€” See changes instantly and confirm results before exporting
  • ๐ŸŽจ 20 built-in themes โ€” From frozen Nordic minimalism to cyberpunk neon, vintage nautical to glitch purple
  • โœ๏ธ Custom color controls โ€” Fine-tune every color: background, roads, water, green spaces, POIs, and text
  • ๐Ÿ“ Custom POI pushpins โ€” Search places through an Amap proxy, save your own POIs, and render them on the exported poster
  • ๐Ÿ“ Multiple export formats โ€” A4 (portrait/landscape), square, phone wallpaper, desktop 16:9, at 300 DPI for high-quality print
  • ๐ŸŒ Multi-language interface โ€” Supports English, Japanese, Korean, Simplified Chinese, German, Spanish, and French
  • ๐Ÿ’พ IndexedDB caching โ€” Previously fetched map data is cached locally for faster regeneration
  • ๐Ÿ”ค Dynamic font loading โ€” Use built-in serif fonts or upload your own TTF/OTF files
  • ๐Ÿ Snake game โ€” Beat boredom while waiting for your poster to generate (inspired by Chrome Dinosaur Game)

How it differs from maptoposter (Python CLI)

This project was inspired by maptoposter (Python CLI) โ€” they each have their own strengths for different use cases:

maptoposter-onlinemaptoposter (Python CLI)
UsageOpen in browser, no install neededCommand-line interface, requires local setup
Best forQuick start, on-the-go usageCommand-line enthusiasts, advanced local customization
Rendering engineRust/WASM (tiny-skia)Python/matplotlib
PlatformCross-browser, any deviceDesktop only (requires Python)

Different tech stacks, same goal โ€” turning your favorite city into unique art.

Local Development

Tech Stack

  • Build โ€” Vite 7 + Bun
  • Frontend โ€” React 19 + TypeScript
  • Styling โ€” Tailwind CSS v4
  • UI components โ€” Radix UI + lucide-react
  • Map data โ€” OpenStreetMap (Overpass API) + Protomaps
  • Rendering โ€” Rust (wasm-pack) + tiny-skia
  • i18n โ€” @inlang/paraglide-js
  • Caching โ€” IndexedDB (idb)

Requirements

Setup

# 1. Install dependencies bun install # 2. Build the Rust/WASM rendering engine # Compile Rust to WebAssembly using wasm-pack cd wasm && wasm-pack build --target web --out-dir ../src/pkg # Or use the npm script: bun run build:wasm # 3. Start the dev server bun run dev # 4. App available at http://localhost:5173

Available Scripts

CommandDescription
bun run devStart dev server
bun run buildBuild for production
bun run build:wasmRebuild WASM engine
bun run previewPreview production build
bun run lintRun linter
bun run fixFormat + lint with auto-fix

Custom POI Setup

The custom POI dialog uses the Amap geocoding API through a proxy endpoint at /api/amap-proxy/.

  1. Apply for your own Amap Web Service API key at the Amap Open Platform.
  2. Configure a proxy endpoint that forwards requests to https://restapi.amap.com/v3/geocode/geo.
  3. Open the Pushpin section in the app, paste the key, test it, then start searching.

Example Cloudflare Worker flow:

export default { async fetch(request: Request) { const url = new URL(request.url); const upstream = new URL("https://restapi.amap.com/v3/geocode/geo"); upstream.search = url.search; return fetch(upstream, { headers: { accept: "application/json", }, }); }, };

Notes:

  • The current frontend assumes the proxy endpoint is /api/amap-proxy/.
  • The frontend sends key, address, and city query parameters to the proxy.
  • Users must provide their own Amap key. Free-tier limits are managed by Amap.

Engineering Notes

Rendering Engine โ€” Rust/WASM

  • Font anti-aliasing โ€” 2ร— supersampling + Box Filter downsampling
  • Road hierarchy lacking depth โ€” Road casing rendered in two passes (stroke first, then fill) + Z-order controls draw sequence by road class
  • Rendering too slow โ€” Douglas-Peucker in screen coordinate space removes subpixel redundancy; single-scan dispatch by feature type

Data Processing

  • Python OSMnx workflow ported โ€” Professional geospatial data processing logic adapted from osmnx
  • Overpass query failures โ€” Auto-splits oversized areas into smaller chunks (2500kmยฒ default limit) to prevent Overpass failures
  • Single node timeout causing long waits โ€” Concurrent requests to 4 mirror servers, fastest response wins

Page Responsiveness

  • Generation blocking the page โ€” Data fetching, projection transforms, and WASM rendering all run in a Web Worker; road precision auto-reduces at large radii
  • Repeated generation taking too long โ€” IndexedDB Gzip-compressed cache, ~100KB per city; direct read on regeneration

License

MIT License โ€” see LICENSE

๐Ÿ’– Support

If this project has saved you time or made your life easier, consider buying me a coffee. Your support is the driving force behind the continued maintenance of this project!

PlatformPayment MethodLink
AfdianWeChat / Alipay๐Ÿ‘‰ Click to Sponsor
Buy Me a CoffeeCredit Card / Apple Pay / Google Pay๐Ÿ‘‰ Click to Sponsor

Acknowledgments

Inspired by @originalankur's maptoposter

Map data provided by OpenStreetMap and Protomaps

Font LXGW Neo ZhiSong (้œž้นœๆ–ฐ่‡ดๅฎ‹) by lxgw, licensed under IPA Font License 1.0

ๅ…ณไบŽ About

โœจโค๏ธโ€๐Ÿ”ฅTurn the cities you love into stunning designs
designfrontendmapsopenstreetmapposterreactrusttailwindcsstypescriptvisualdesignvitewasmwebassembly

่ฏญ่จ€ Languages

TypeScript65.5%
Rust23.8%
JavaScript9.8%
CSS0.6%
PowerShell0.2%
HTML0.1%

ๆไบคๆดป่ทƒๅบฆ Commit Activity

ไปฃ็ ๆไบค็ƒญๅŠ›ๅ›พ
่ฟ‡ๅŽป 52 ๅ‘จ็š„ๅผ€ๅ‘ๆดป่ทƒๅบฆ
65
Total Commits
ๅณฐๅ€ผ: 15ๆฌก/ๅ‘จ
Less
More

ๆ ธๅฟƒ่ดก็Œฎ่€… Contributors