The Problem

Designers and hobbyists need a quick way to turn any location’s OpenStreetMap data into a print‑ready poster. Existing tools are either manual (export from GIS software) or locked behind proprietary services, making iteration slow and costly.

What This Does

TerraInk is a React‑based web app that renders vector tiles with MapLibre, applies a theme system, and exports the result as high‑resolution PNG or PDF. The core rendering pipeline lives in src/features/poster/infrastructure/renderer/ (e.g., canvas.ts, layers.ts, typography.ts). The UI for map interaction and export lives under src/features/ – for example, src/features/export/ui/DesktopExportFab.tsx triggers the exporters in src/features/export/infrastructure/ (pngExporter.ts, pdfExporter.ts). Application bootstrap is in src/main.tsx, which mounts <App /> from src/App.tsx.

How To Use It

Setup

The project uses Bun as the package manager (see bun.lock and the “Bun” badge in the README). Install dependencies with:

bun install

A Docker build is also provided; the image can be built and run with:

docker compose up --build

Configuration

Copy the example environment file and fill any required keys (e.g., a MapLibre tile endpoint or Google Fonts API key). The repo includes .env.example but does not list concrete variable names, so you must inspect src/core/config.ts to see the expected keys (e.g., VITEMAPTILES_URL).

cp .env.example .env edit .env as needed

Running

For local development with hot‑reloading (Vite is configured in vite.config.js), start the dev server:

bun run dev # falls back to npm run dev if a script exists

The entry point is src/main.tsx, which renders the React tree into index.html. In production, the Docker image serves the built assets via the included nginx.conf.

Real‑World Use

A marketing team could embed TerraInk in an internal portal to let campaign designers generate city‑specific posters on demand. Example workflow:

import { useExport } from '@/features/export/application/useExport';

function GeneratePosterButton({ location }) { const exportPoster = useExport(); return ( <button onClick={() => exportPoster({ location, theme: 'retro', format: 'png' })}> Download Poster </button> ); }

The button calls the same export logic used by the built‑in FAB components, producing a ready‑to‑print PNG.

Code Health & Issues

Medium – No test suite – No .test. files; code paths are unverified. Medium – Missing CI/CD – .github/ contains only a PR template; no workflow files. Low – No lockfile for npm – Only bun.lock is present; package-lock.json is absent, risking nondeterministic installs for npm users. Low – Potential runtime errors – Export modules (src/features/export/infrastructure/) lack explicit error handling for network failures when fetching tiles. Low – Configuration visibility – Required env vars are not documented; developers must read src/core/config.ts to discover them. Low – License present – LICENSE file exists (MIT), so reuse is permitted.

The Bottom Line

TerraInk provides a functional, self‑hostable poster generator built on modern web tooling (React, Vite, MapLibre). It is suitable for small teams or individual creators who can accept the current lack of automated testing and CI. To adopt it in production, add a test suite, CI pipeline, and clearer environment‑variable documentation.