# Tileflow Agent Guide Tileflow is a developer-first map platform. It is designed so a developer or AI coding agent can complete the full map loop in files and commands: 1. Style the map in `tileflow.config.ts`. 2. Run `tileflow validate` for deterministic feedback. 3. Preview through the app dev server. 4. Deploy stable MapLibre style URLs. 5. Use the same named map from React, Vue, Svelte, or MapLibre. This avoids GUI-only handoffs. The source of truth stays in the repository, so changes can be generated, reviewed, tested, and deployed like product code. Local config, validation, and preview require no account or API key. Hosted deploys currently require approved access and a pre-provisioned project key. ## Install ```bash pnpm add @tileflow/core@alpha maplibre-gl # Choose one runtime: pnpm add @tileflow/react@alpha pnpm add @tileflow/vue@alpha pnpm add @tileflow/svelte@alpha # Choose one framework adapter: pnpm add @tileflow/vite@alpha pnpm add @tileflow/next@alpha pnpm add @tileflow/webpack@alpha pnpm add -D @tileflow/cli@alpha ``` ## Create a config Run: ```bash tileflow init ``` Then edit `tileflow.config.ts`: ```ts import {defineTileflow, osm, roads} from '@tileflow/core'; export default defineTileflow({ themes: { light: { colors: { background: '#F6F7F3', land: '#F1F3ED', water: '#A9D3F5', park: '#CDE8B5', building: '#E6E3DA', road: '#FFFFFF', roadMajor: '#F4C95D', boundary: '#C9D1D9', text: '#3C4043', textMuted: '#727B84', textHalo: '#FFFFFF', }, modules: { roads: { primary: '#F4C95D', }, }, }, }, tilesets: { world: { id: 'world', name: 'World', attribution: 'OpenMapTiles and OpenStreetMap contributors', }, }, maps: { madrid: { basemap: osm(), name: 'Madrid', tileset: 'world', theme: 'light', typography: { font: 'Noto Sans', weight: 'regular', }, density: 'balanced', modules: [roads({preset: 'standard'})], labels: 'balanced', poi: 'minimal', allowedOrigins: ['example.com', '*.example.com'], }, }, }); ``` ## Semantic style fields Prefer the Tileflow config API over raw MapLibre layer JSON: - `colors.background`: map background. - `colors.land`: land fill. - `colors.water`: water fill. - `colors.park`: parks and natural areas. - `colors.building`: building fill. - `colors.road`: road base color. - `colors.roadMajor`: major road base color. - `colors.text`: label text. - `colors.textMuted`: secondary label text. - `colors.textHalo`: label halo. - `theme.modules.`: optional module-specific tokens, for example `theme.modules.roads.primary`. - `modules`: semantic behavior helpers such as `roads()`, `labels()`, `poi()`, and `styleOverride()`. - `roads({preset})`: road-network behavior. Presets are `minimal`, `standard`, `navigation`, or `detailed`. - `roads({detail})`: `none`, `major`, `streets`, or `all`. - `roads({hierarchy, weight, casing})`: hierarchy is `subtle`, `clear`, or `strong`; weight is `thin`, `regular`, or `bold`; casing is `none`, `subtle`, or `strong`. - `roads({extras})`: independently enables `paths`, `rail`, and `ferry`. Road colors always remain in `theme.colors` or `theme.modules.roads`. - `layers`: exact MapLibre layer patches when semantic fields are not enough. - `typography.font`: label font family. - `typography.weight`: `regular`, `medium`, `semibold`, or `bold`. - `density`: `clean`, `balanced`, or `dense`. - `roads`: legacy shorthand accepting `hidden`, `soft`, `standard`, or `detailed`; prefer the `roads()` module for new configs. - `labels`: `none`, `essential`, `balanced`, or `full`. - `poi`: `none`, `minimal`, `balanced`, or `full`. - `tileset`: named tileset used by the map. - `allowedOrigins`: browser-origin allowlist that reduces unauthorized embedding. It is not authentication and does not make map data private. This small surface is intentional. It is easy for agents to generate, easy for humans to review, and easy for `tileflow validate` to check. ## Framework adapters Add the Vite plugin: ```ts import react from '@vitejs/plugin-react'; import {defineConfig} from 'vite'; import {tileflow} from '@tileflow/vite'; export default defineConfig({ plugins: [react(), tileflow()], }); ``` For Webpack 5: ```ts import {TileflowWebpackPlugin} from '@tileflow/webpack'; export default { plugins: [new TileflowWebpackPlugin()], }; ``` For Next.js, wrap `next.config.ts`: ```ts import {withTileflow} from '@tileflow/next'; import type {NextConfig} from 'next'; const nextConfig: NextConfig = {}; export default withTileflow(nextConfig); ``` Then add `app/api/tileflow/[[...tileflow]]/route.ts`: ```ts import {createTileflowRouteHandlers} from '@tileflow/next/server'; export const runtime = 'nodejs'; export const dynamic = 'force-dynamic'; export const {GET, HEAD} = createTileflowRouteHandlers({ routeBase: '/api/tileflow', }); ``` During development, framework adapters serve: ```txt /tileflow/manifest.json /tileflow/styles/:mapName.json ``` ## Runtime components Render a named map with `@tileflow/react`: ```tsx import {Map} from '@tileflow/react'; import 'maplibre-gl/dist/maplibre-gl.css'; export function MadridMap() { return ; } ``` Vue apps can use the same map name: ```vue ``` Svelte apps can use the same map name: ```svelte ``` In local development, runtime components resolve through `/tileflow/manifest.json`. In production, they resolve through the manifest written during deploy or build. Runtime components accept `mapOptions` for native MapLibre constructor options except `container` and `style`, which Tileflow resolves from named maps and manifests. Direct props such as `center`, `zoom`, and `interactive` take priority when provided. ## How Tileflow works The basic pipeline is: ```txt tileflow.config.ts -> @tileflow/core compiler -> MapLibre style JSON -> hosted style URL -> TileJSON + vector tiles + glyphs + sprites -> React, Vue, Svelte, MapLibre, or Static Maps -> usage and deployment status ``` Use `https://tileflow.dev/docs/how-it-works` when an agent needs the product model, asset anatomy, or frontend manifest shape. ## Validate Always validate after changing config: ```bash tileflow validate ``` If validation fails, edit `tileflow.config.ts` and run the command again. Do not deploy until validation succeeds. ## Preview For Vite, Next, and Webpack apps: ```bash pnpm dev ``` For standalone preview or custom apps: ```bash tileflow dev ``` ## Deploy Hosted account access is restricted to approved Google accounts. Approved users can authorize the CLI through the dashboard: ```bash tileflow login ``` An existing project key can still be stored manually: ```bash tileflow login --manual ``` Then deploy: ```bash tileflow validate tileflow deploy ``` Deploy compiles selected map styles in memory, uploads them to Tileflow, and writes `public/tileflow/manifest.json` locally by default. The manifest contains stable hosted MapLibre style URLs for production apps. For CI, set `TILEFLOW_API_KEY` and run validation before deploy. ## Auth and keys Use API keys only from trusted environments: - Local dev: framework adapters and `tileflow dev` serve local styles without a browser API key. - CLI: `tileflow login` uses the approved dashboard device flow; `tileflow login --manual` stores an existing project key. `tileflow whoami` and `tileflow logout` inspect or remove that local credential. - CI/server: set `TILEFLOW_API_KEY` and call the CLI or API with `Authorization: Bearer`. - Browser production: use `allowedOrigins` to reduce unauthorized embedding instead of putting API keys in client code. Treat hosted map IDs and rendered data as public. Dashboard-created project keys have two permission levels: - `Full access`: publish styles, manage tilesets, inspect project status, and render static maps. - `Static maps only`: create or precache static map images without changing project resources. Common scopes: - `styles:write`: deploy styles and manage tilesets through current write routes. - `static:write`: create or precache static map scenes. - `tilesets:write`: manage tilesets when a key is scoped specifically for tileset writes. ## Tilesets Tilesets connect named maps to vector data. The default public tileset is `world`. ```bash export TILEFLOW_API_KEY=tf_live_... tileflow tileset register --id madrid --name Madrid tileflow tileset upload ./madrid.pmtiles --id madrid tileflow status tileflow deploy --tileset madrid ``` `world` and `terrain` are reserved, operator-managed global IDs. Project registration derives an isolated R2 key and does not accept `--r2-key`. Proxied PMTiles uploads are validated and limited to 32 MiB before the active manifest changes. Tileflow serves TileJSON and exact versioned vector tile responses from Cloudflare R2 using range reads. Hosted production terrain is preseed/cache-only: a cache miss returns 404 and never triggers an upstream download or R2 write. ## Static maps Use static maps for deterministic PNG output from the same deployed style. ```ts import {createStaticMap, marker} from '@tileflow/static'; const result = await createStaticMap( { map: 'madrid', camera: { type: 'center', center: [-3.7038, 40.4168], zoom: 12, }, size: { width: 1200, height: 800, }, overlays: [marker({coordinate: [-3.7038, 40.4168]})], }, { apiKey: process.env.TILEFLOW_API_KEY, }, ); ``` React apps can render static scenes with `StaticMap` from `@tileflow/react/static`. Keep API keys on the server; use a local app route as the `createUrl`. ## Hosted routes Tileflow serves the primitives MapLibre expects: ```txt GET /maps/:mapId/style.json GET /tiles/:tilesetId/tiles.json GET /tiles/:tilesetId/:version/:z/:x/:y.pbf GET /fonts/:fontstack/:range.pbf GET /sprites/:spriteId/sprite.json GET /sprites/:spriteId/sprite.png GET /v1/styles/:projectId/:environment.json GET /maps/:mapId/static.png # development/self-hosting only; hosted production returns 403 GET /static-maps/v1/:hash.png POST /v1/styles POST /v1/tilesets PUT /v1/tilesets/:tilesetId/archive.pmtiles POST /v1/static/maps POST /v1/static/maps/precache POST /v1/usage # usage:write plus an 8-128 character Idempotency-Key GET /v1/usage/summary GET /v1/billing/config # checkout remains disabled in hosted production GET /v1/status GET /v1/me ``` Static map scene limits: - Width and height: 64 to 1280 pixels. - Pixel budget: 1280 x 1280 physical pixels. - Overlays: up to 24. - Path coordinates: up to 2000. - Overlay JSON: up to 96 KB. ## Suggested agent rule file Add this to starter repos as `CLAUDE.md`, `.cursorrules`, or another agent instruction file: ```md # Tileflow map workflow - Style maps in `tileflow.config.ts`. - Prefer Tileflow semantic fields over raw MapLibre layer JSON. - Use named maps from React: ``. - After every config change, run `tileflow validate`. - Preview through the app dev server before deploy. - Deploy with `tileflow deploy` only after validation succeeds. ``` ## What agents should not do by default - Do not require the user to open a visual style editor. - Do not create large raw MapLibre style JSON files unless requested. - Do not paste API keys into source files. - Do not bypass `tileflow validate`. - Do not deploy before previewing when the user expects a visual result.