Freestiler
A Rust-powered vector tile generator for R, Python, and DuckDB.
Install / Use
/learn @walkerke/FreestilerREADME
freestiler <a href="https://walker-data.com/freestiler/"><img src="man/figures/logo.png" align="right" height="139" alt="freestiler logo" /></a>
<!-- badges: start --> <!-- badges: end -->freestiler creates PMTiles vector tilesets from R and Python. Give it an sf object, a file on disk, or a DuckDB SQL query, and it writes a single .pmtiles file you can serve from anywhere. The tiling engine is written in Rust and runs in-process, so there's nothing else to install.
Installation
R
Install from r-universe:
install.packages(
"freestiler",
repos = c("https://walkerke.r-universe.dev", "https://cloud.r-project.org")
)
Or install from GitHub:
# install.packages("devtools")
devtools::install_github("walkerke/freestiler")
Python
pip install freestiler
Published PyPI wheels currently target Python 3.9 through 3.14.
See the Python Setup article for more details.
Quick start
The main function is freestile(). Let's tile the North Carolina counties dataset that ships with sf:
library(sf)
library(freestiler)
nc <- st_read(system.file("shape/nc.shp", package = "sf"))
freestile(nc, "nc_counties.pmtiles", layer_name = "counties")
That's useful for checking your installation, but the same API handles much bigger data. Here we tile all 242,000 US block groups from tigris:
library(tigris)
options(tigris_use_cache = TRUE)
bgs <- block_groups(cb = TRUE)
freestile(
bgs,
"us_bgs.pmtiles",
layer_name = "bgs",
min_zoom = 4,
max_zoom = 12
)
Viewing tiles
The quickest way to view a tileset is view_tiles(), which starts a local server and opens an interactive map:
view_tiles("us_bgs.pmtiles")
For more control, use serve_tiles() to start a local server and build your map with mapgl:
library(mapgl)
serve_tiles("us_bgs.pmtiles")
maplibre(hash = TRUE) |>
add_pmtiles_source(
id = "bgs-src",
url = "http://localhost:8080/us_bgs.pmtiles",
promote_id = "GEOID"
) |>
add_fill_layer(
id = "bgs-fill",
source = "bgs-src",
source_layer = "bgs",
fill_color = "navy",
fill_opacity = 0.5,
hover_options = list(
fill_color = "#ffffcc",
fill_opacity = 0.9
)
)
The built-in server handles CORS and range requests automatically. For tilesets larger than ~1 GB, use an external server like npx http-server /path --cors -c-1 for better performance. See the Mapping with mapgl article for a full walkthrough.
DuckDB queries
If your data lives in DuckDB, freestile_query() lets you filter, join, and transform with SQL before tiling:
freestile_query(
query = "SELECT * FROM read_parquet('blocks.parquet') WHERE state = 'NC'",
output = "nc_blocks.pmtiles",
layer_name = "blocks"
)
For very large point datasets, the streaming pipeline avoids loading the full result into memory. On a recent run, freestile_query() streamed 146 million US job points from DuckDB into a 2.3 GB PMTiles archive in about 12 minutes:
freestile_query(
query = "SELECT naics, state, ST_Point(lon, lat) AS geometry FROM jobs_dots",
output = "us_jobs_dots.pmtiles",
db_path = db_path,
layer_name = "jobs",
tile_format = "mvt",
min_zoom = 4,
max_zoom = 14,
base_zoom = 14,
drop_rate = 2.5,
source_crs = "EPSG:4326",
streaming = "always",
overwrite = TRUE
)
Direct file input
You can tile spatial files without loading them into R first:
# GeoParquet
freestile_file("census_blocks.parquet", "blocks.pmtiles")
# GeoPackage, Shapefile, or other formats via DuckDB
freestile_file("counties.gpkg", "counties.pmtiles", engine = "duckdb")
Multi-layer tilesets
pts <- st_centroid(nc)
freestile(
list(
counties = freestile_layer(nc, min_zoom = 0, max_zoom = 10),
centroids = freestile_layer(pts, min_zoom = 6, max_zoom = 14)
),
"nc_layers.pmtiles"
)
Tile formats
freestiler defaults to MapLibre Tiles (MLT), a columnar encoding that produces smaller files for polygon and line data. Use tile_format = "mvt" when you need the widest viewer compatibility.
Learn more
- Getting Started - full tutorial
- Mapping with mapgl - viewing and styling tiles with mapgl
- MapLibre Tiles (MLT) - MLT vs MVT and when to use each
- Python Setup - Python installation and usage
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
