Try it live: map-paper.pages.dev
Make a poster or a wallpaper out of any place on Earth. There are 41 styles to pick from. Some copy old cartography, some borrow from map apps, and the rest are made up. Everything renders live in the browser and exports big enough to print.
You need Node.js 18 or newer, and a browser that supports WebGL. Chrome, Edge, Firefox and Safari all work. There is nothing to sign up for and no API key to get.
git clone https://github.com/deepakvettickal/map-paper.git
cd map-paper
npm install
npm run devOpen http://localhost:5173. It takes a moment on first load while the map tiles come down.
Then:
- Search for a place in the sidebar. You can also drag and scroll the poster to frame it yourself.
- Pick a style, then change any of the colours, fonts, border and text if you want to.
- Choose a size. A4, A3, square, phone, or 4K desktop. Paper sizes also have a DPI setting.
- Hit Download PNG and the file goes to your downloads folder.
Save config writes the whole poster to a JSON file: the style, every colour, the place, the text and the output size. Load config puts it all back. Handy for keeping a look you like, or sending one to someone else.
In a hurry, or just browsing? Surprise me picks a style, a city and a fresh palette for you. The three squares in the corner switch the interface between light, dark and AMOLED black.
You can link straight to a style and a place: ?style=nolli&lat=51.5&lng=-0.12&zoom=14&size=desktop.
Other commands:
npm run build # typecheck and build to dist/
npm run preview # serve the production build
npm run typecheck # types onlyIf something looks wrong. A blank map usually means the browser window was behind another one. Browsers stop drawing WebGL in the background, so bring the window to the front and it will come back. If an export fails with a size error, drop the DPI. Very large canvases go past what some graphics cards allow.
Each style is a single JSON file in src/styles/, so adding one means adding a file rather
than writing code. Every style also opens at a place that suits it, which is what you see below.
![]() Solarized Light - after Ethan Schoonover's Solarized Light Copenhagen, Denmark |
![]() Solarized Dark - after Ethan Schoonover's Solarized Dark Seattle, United States |
These borrow the thinking behind each map: how colour is used, how road types are ranked, the overall mood. No assets or code are taken from them.
Colour themes from prettymaps and prettymapp, rebuilt on this engine.
- Vector tiles instead of API calls. OpenFreeMap tiles are drawn on the GPU by MapLibre GL. Panning, zooming and restyling happen straight away, and nothing is re-fetched when a colour changes.
- Styles are just data. A
StyleSpeccarries the colours, road widths for each class, pattern fills, fonts, frame and effects.src/engine/buildMapStyle.tsturns that into a MapLibre style. - The art renderer.
src/engine/patterns.tsbuilds hatching, crosshatch, stipple, waves and dot fills as they are needed.src/engine/effects.tsthen runs a single WebGL pass over the finished poster for paper texture, grain, shaky lines, ink misregistration, pixelation and vignetting. Everything is measured in poster units, which is why a 300 DPI export looks like the preview. There is a switch and a strength slider in the sidebar. - Export. A hidden map renders at a higher pixel ratio, then the frame, text and effects are composited on top. A4 at 300 DPI finishes in well under a second on a normal graphics card.
src/
config/ style + poster types, paper and wallpaper sizes
styles/ one JSON file per style
engine/ style builder, pattern generator, effects shader, PNG export
poster/ the poster component and its frame/text overlay
ui/ sidebar controls
services/ place search (Nominatim)
scripts/ snapshot, contact-sheet and gallery tooling
node scripts/snap.mjs out/ nolli pencil # screenshot styles with the local Chrome
node scripts/contact-sheet.mjs out/ # lay them out side by side
node scripts/gallery.mjs [ids…] # rebuild the README gallery
node scripts/hero.mjs [a] [b] [lat] [lng] [zoom] # rebuild the split hero imageCLAUDE.md has the architecture notes and what is planned next, including 3D terrain and buildings, and map ornaments like compass roses and cartouches.
- Add more styles
- Publish and serve the tool, for access without cloning the repo
- Let people send in a palette they made with Surprise me, so good ones can become styles
- Build a gallery of posters people have made, replayed live from their saved configs
Bigger plans such as 3D terrain, map ornaments and SVG or PDF export are listed in CLAUDE.md.
The site is a static build plus one serverless function on Cloudflare Pages; see DEPLOY.md.
Usage is counted anonymously: visits, exports, randomisations and config saves. There are no cookies, no
fingerprinting and no third-party analytics, and the session id lives in sessionStorage, so it is gone when
the tab closes. Downloads also record the poster config, which is what the planned gallery will replay.
The browser never touches the database. Events go to this site's own /api/event, which holds the
credentials and writes to Firestore; firestore.rules denies every client read and write.
| Project | Licence | Role |
|---|---|---|
| MapLibre GL JS | BSD-3-Clause | GPU map rendering |
| OpenStreetMap | ODbL | all map data, © OpenStreetMap contributors |
| OpenFreeMap | free public tiles | planet-wide vector tiles, no API key |
| Nominatim | data ODbL | place search |
| React, Vite, Zustand, TypeScript | MIT / Apache-2.0 | app framework, build, state, types |
| Puppeteer | Apache-2.0 | the screenshot and gallery tooling |
| Google Fonts | OFL | every typeface in the poster text picker |
One row per style, in the order they appear in the app. The historic maps are long out of copyright, but their makers are named here anyway. Styles marked original are new designs, so there is nobody to credit.
| Style | Inspiration |
|---|---|
| Nolli | After Giambattista Nolli, Nuova Pianta di Roma (1748) |
| Sanborn | After the Sanborn fire-insurance maps (1867–1970s) |
| Snow | After John Snow's cholera map of Soho (1854) |
| Booth | After Charles Booth's Descriptive Map of London Poverty (1889) |
| Ordnance | After the Ordnance Survey first edition (1840s-80s) |
| Harry Beck | After Harry Beck's London Underground diagram (1933) |
| Vignelli | After Massimo Vignelli's New York City subway map (1972) |
| Blueprint | After architectural cyanotype blueprints |
| Cyanotype | After Anna Atkins' cyanotype photograms (1840s) |
| Soviet Topo | After Soviet military topographic maps |
| Bauhaus | After the Bauhaus school and Swiss International Style |
| Art Deco | After 1920s-30s Art Deco posters |
| Ukiyo-e | After Edo-period Japanese woodblock maps |
| Stained Glass | original - Gothic stained-glass windows |
| Starry Night | After Vincent van Gogh, The Starry Night (1889) |
| Risograph | After risograph and screenprinted zines |
| Linocut | original - carved linoleum block prints |
| Pencil | original - graphite sketchbook |
| Watercolor | Inspired by Stamen Watercolor |
| Pastel | original - soft pastels on warm beige |
| Sakura | original - cherry blossom in spring |
| Solarpunk | original - the solarpunk palette of sun and greenery |
| Dune | original - desert ochres and deep shade |
| Nordic | original - pale northern light |
| Toner | Inspired by Stamen Toner |
| Night | Inspired by CARTO Dark Matter |
| Neon | original - neon signs after dark |
| GMaps Dark | Inspired by the dark mode of Google Maps |
| Search | Inspired by the light mode of Google Maps |
| Drive | Inspired by the design philosophy of Waze |
| Here | Inspired by the design philosophy of HERE Maps |
| Synthwave | original - 80s retro-futurism |
| Brutalist | original - raw concrete architecture |
| Circuit | original - printed circuit boards |
| 8-bit | original - handheld pixel-art games |
| Solarized Light | After the Solarized Light palette by Ethan Schoonover |
| Solarized Dark | After the Solarized Dark palette by Ethan Schoonover |
| Heerhugowaard | Tribute to prettymaps by Marcelo Prates |
| Peach | The Peach theme from prettymapp by Christoph Rieke |
| Auburn | The Auburn theme from prettymapp by Christoph Rieke |
| Citrus | The Citrus theme from prettymapp by Christoph Rieke |
The map-app styles take inspiration from how those maps are designed. They do not copy any assets, code or map styles, and this project is not affiliated with or endorsed by those companies.
map-paper builds on the work of these open source projects.
- prettymaps by Marcelo Prates, which started artistic OpenStreetMap posters. Its inked look and JSON presets shaped how styles are described here, and the Heerhugowaard style is a tribute to its preset of the same name.
- prettymapp by Christoph Rieke, a tidier take on prettymaps with a friendly web UI.
- terraink by Yousif Amanuel, which shows how fast and polished a browser-based poster maker can be when it is built on vector tiles and MapLibre.
None of the AGPL-licensed code was copied. The ideas were rebuilt from scratch.
- MapLibre GL JS for GPU map rendering
- OpenFreeMap for free vector tiles
- OpenStreetMap for map data © OpenStreetMap contributors
- Nominatim for place search
Fixes and ideas are welcome. To propose a change:
- Fork the repo (or create a branch if you have push access), and start from an up-to-date
main:git checkout main && git pull. - Branch for your change:
git checkout -b my-change. - Make the change and check it still builds:
npm run build(this also typechecks). If you touched a style, look at a screenshot — style work can't be verified by reading JSON. - Commit and pu










































0 comments
log in to comment.