maplibre-pmtiles-patterns について
PMTiles を使って MapLibre GL JS の地図を開発する人向けの実用スキルです。アーカイブの生成とホスティング、HTTP Range による配信、プロトコル互換性やズーム動作を含む MapLibre 連携を説明します。
主な機能
- 01PMTiles とタイルサーバーの選択
- 02タイルアーカイブの生成と変換
- 03HTTP Range 対応ホストでの配信
- 04PMTiles と MapLibre GL JS の接続
- 05CLI によるアーカイブの確認と検証
活用シーン
- 01タイルサーバーなしで静的マップを公開
- 02CDN から地域タイルデータを配信
- 03ベクター、ラスタ、高度タイルを連携
- 04MapLibre のプロトコルやズーム問題を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ maplibre/ maplibre-agent-skills --skill maplibre-pmtiles-patternsインストール後、Claude Code で/maplibre-pmtiles-patternsを入力して読み込まれたか確認します。
詳細
MapLibre PMTiles のパターン
PMTiles は、ベクターまたはラスターのマップタイルを格納する単一ファイル形式です。任意の静的ホストに 1 つ(または少数)のファイルをホストすると、MapLibre が HTTP 経由でバイト範囲をリクエストします。タイルサーバーも動的なバックエンドも必要ありません。このスキルでは、PMTiles を使用する場面、生成してホストする方法、MapLibre GL JS に接続する方法を説明します。
このスキルを使用する場面
- タイルサーバーを実行せずにマップタイルをホストする場合(S3、Cloudflare R2、GitHub Pages など)
- 完全に静的、またはサーバーレスのマップスタックを構築する場合
- 大規模なタイルセットをレンジリクエスト対応の CDN から配信する場合
- OSM やその他のソースから PMTiles を生成する場合(Planetiler、tippecanoe)
- Overture Maps などの単一ファイルのタイルデータセットを MapLibre で使用する場合
PMTiles とは何か、その重要性
- ベクターとラスター — PMTiles は両方に対応しています。ファイルには、ベクターレイヤー(水域、道路、POI など)、ラスター画像(PNG/JPEG)、またはラスター DEM(標高データ。地形用の Terrarium 形式など)を格納できます。スタイルでは、それに応じて
type: 'vector'、type: 'raster'、またはtype: 'raster-dem'を使用します。 - マップごとに 1 つのファイル — 通常、1 つの
.pmtilesファイルには、タイルピラミッド全体(すべてのズームレベル)とすべてのレイヤー(ベクターまたはラスター)が 1 つのアーカイブに格納されます。この形式では、コンパクトなレイアウト(Hilbert 曲線など)でタイルを保存するため、クライアントは必要なバイト範囲だけをリクエストできます。広範囲をカバーする場合は、地域ごとに複数のファイルに分割できます。 - HTTP レンジリクエスト — クライアントは必要なバイト範囲(タイル 1 枚など)だけをリクエストするため、サーバーが x/y/z を理解する必要はありません。
Rangeヘッダーに対応したホストならどれでも使用できます。 - 配信 — 静的ストレージ(S3、R2、GitHub Pages、Netlify)から直接配信できます。クライアントがレンジリクエストを使用するため、タイルサーバーは不要です。また、tileserver-gl や Martin を使って PMTiles を配信することもできます(ローカルパス、HTTP URL、S3 に対応)。スタイル、グリフ、その他のソースも提供するサーバーを 1 つ用意したい場合に便利です。
- 作成 — MBTiles から変換する(PMTiles CLI)か、ソースデータから生成する(Planetiler、tippecanoe、GDAL など)ことで PMTiles を作成できます。また、Protomaps は、構築済みの PMTiles(グローバルまたは地域別のベースマップなど)をダウンロードして自分で配信したり、PMTiles CLI でカスタムの抽出データを作成したりできるプロバイダーです。自分で OSM から生成する必要はありません。Protomaps のベースマップは OpenStreetMap データを基に構築されています。これらを使用するマップでは、OSM の帰属表示が必須です。以下の PMTiles CLI と PMTiles の生成 を参照してください。
- CDN に適しています — レンジリクエストはキャッシュとの相性がよいため、ファイルを CDN の背後に置けば、世界中へ高速に配信できます。
従来のタイルサーバーより PMTiles が適している場面:
- サーバー側のロジックを一切使いたくない場合(静的ホスティングのみ)。
- 1 つまたは少数のファイルに収まる、範囲が限定されたデータセット(国、地域、テーマ)がある場合。
- デプロイを簡単にし、運用負荷を抑えたい場合(ファイルをアップロードしてキャッシュヘッダーを設定すれば完了)。
タイルサーバー(tileserver-gl、Martin など)のほうが適している場面:
- データベース(PostGIS)から動的なタイルを生成する必要がある場合、またはデータを頻繁に更新する場合。
- 非常に大規模なグローバルデータセットがあり、オンデマンドまたは地域単位でのみタイルを生成したい場合。
MapLibre との統合:PMTiles プロトコル
MapLibre は PMTiles にネイティブ対応していません。PMTiles ライブラリを使ってプロトコルハンドラーを追加すると、pmtiles://(または .pmtiles ファイルへの https://)ソースを使用できるようになります。
インストール:
npm install pmtiles
プロトコルを登録してスタイルで使用する:
import * as pmtiles from 'pmtiles';
import * as maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
// Add PMTiles protocol so sources can reference .pmtiles URLs
const protocol = new pmtiles.Protocol();
maplibregl.addProtocol('pmtiles', protocol.tile);
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {
tiles: {
type: 'vector',
url: 'pmtiles://https://example.com/data.pmtiles'
}
},
layers: [
{
id: 'background',
type: 'background',
paint: { 'background-color': '#f8f4f0' }
},
{
id: 'water',
type: 'fill',
source: 'tiles',
'source-layer': 'water',
paint: { 'fill-color': '#a0c8f0' }
}
// add more layers as needed — each uses the same source, different 'source-layer'
]
},
center: [0, 0],
zoom: 2
});
// Optional: remove protocol on map teardown
// map.on('remove', () => maplibregl.removeProtocol('pmtiles'));
MapLibre GL JS 4.0.0 で addProtocol が変更されました。 v3 の (params, callback) シグネチャーは廃止されています。4.0.0 の変更履歴には「addProtocol をコールバックなしの Promise ベースに変更し、キャンセル可能にする」と記載されています。ハンドラーは async (params, abortController) となり、data プロパティを持つオブジェクト({data, cacheControl?, expires?})を返す必要があります。ArrayBuffer、Blob、Response、Uint8Array をそのまま返すのは仕様に沿っていません。MapLibre はハンドラーが返す値の .data を読み取るため、バッファーをそのまま返すとデータがないものとして扱われ、arrayBuffer リクエストには空の ArrayBuffer(0) が返されます。その結果、エラーになるのではなくタイルが空白になります。ハンドラーは、最初のマップを作成する前に一度、モジュールに登録してください(maplibregl.addProtocol(...) または名前付きの addProtocol インポート)。プロトコルレジストリーはグローバルなので、一度登録すればページ上のすべてのマップで使用できます。
// ❌ v3 — on v4+ the second argument is an AbortController, so callback(...) throws,
// and the returned {cancel} has no data: the tile comes back blank
maplibregl.addProtocol('custom', (params, callback) => {
fetch(params.url)
.then((r) => r.arrayBuffer())
.then((buffer) => callback(null, buffer))
.catch((error) => callback(error));
return { cancel: () => {} };
});
// ✅ v4+ — async (params, abortController) resolving to {data}
maplibregl.addProtocol('custom', async (params, abortController) => {
const response = await fetch(params.url, { signal: abortController.signal });
if (!response.ok) throw new Error(`Tile fetch error: ${response.statusText}`);
const buffer = await response.arrayBuffer();
return { data: buffer }; // the {data} wrapper is required; a bare buffer is not
});
PMTiles を使う場合、コードを変更する必要はありません。 new pmtiles.Protocol().tile は、ライブラリーの v4 ハンドラーを v3compat シムでラップしたものです(pmtiles ≥ 3.0.0)。第 2 引数が AbortController かどうかを確認して適切に処理するため、maplibregl.addProtocol('pmtiles', protocol.tile) の1行は GL JS v3、v4、v5、v6 で正しく動作し、すでに {data: Uint8Array, cacheControl, expires} を返します。pmtiles 2.x を使い続けているプロジェクトでは、tile がコールバック専用のため、MapLibre と合わせてライブラリーもアップグレードする必要があります。独自のハンドラーを作成する場合や、手作業で実装したコールバックハンドラーが v4 へのアップグレードで動作しなくなった場合は、上記の仕様に従ってください。
レイヤーの参照: スタイルには、.pmtiles URL を指すソース(例:sources.tiles)を1つ定義します。そのファイルから描画する layers 配列内の各レイヤーでは、source: 'tiles' と "source-layer": "layerName" を使用します。ここで layerName は、タイルで使われているスキーマに応じて、ファイル内のベクターレイヤー名を指定します。同じファイルから道路、ラベルなどを表示するには、source-layer の値を変えたスタイルレイヤーを複数追加します。
重要: url は pmtiles://https://...(プロトコル + .pmtiles ファイルの HTTPS URL)にできます。ライブラリーは範囲リクエストを使ってファイルを取得します。ラベルやアイコンを使う場合は、スタイルで引き続きグリフとスプライトを定義する必要があります(maplibre-source-wiring を参照)。
ズーム範囲はヘッダーから取得します — tiles: ではなく url: を使ってください。 PMTiles アーカイブには、ヘッダーに独自の最小ズームと最大ズームが保存されています。url: 'pmtiles://https://...' で参照すると、プロトコルがヘッダーを読み取り、正しい minzoom/maxzoom を含む TileJSON を MapLibre に渡すため、アーカイブの最大ズームを超えるズームも自動的にオーバーズームされ、maxzoom を手動で設定する必要はありません。代わりに tiles: ['pmtiles://.../{z}/{x}/{y}'] のテンプレートを手動で設定すると、このヘッダーの参照が省略されます。プロトコルはアーカイブの最大ズームまでは引き続きタイルごとのリクエストに応答するため、ハンドラーの不足や 404 の問題ではありません。しかし、ズーム範囲が指定されていない MapLibre は maxzoom: 22 とみなし、アーカイブに存在しないズームレベルもリクエストし続けるため、オーバーズームされずに空のデータが返されます(ベクタータイルは空白、ラスタタイルは何も表示されません)。必ず url: を使ってください。
❌ ソースのタイル位置を指定するプロパティは url と tiles の2つだけです。 MapLibre のスタイル仕様では、vector、raster、raster-dem のソースに tileset プロパティはありません。ズーム範囲が正しくない場合は、どちらを使ったかを見直してください。3つ目のプロパティを使おうとしないでください。
ラスタとラスタ DEM: 同じプロトコルでラスタ PMTiles も使えます。画像には type: 'raster' のソースを使用してください。地形・標高には "encoding": "terrarium"(または "mapbox")を指定した type: 'raster-dem' のソースを使用すると、MapLibre で陰影起伏や 3D 地形を適用できます。その後、スタイルの terrain プロパティで参照します。ソースの例:
"elevation": {
"type": "raster-dem",
"url": "pmtiles://https://example.com/elevation.pmtiles",
"encoding": "terrarium"
}
React で PMTiles を使用する場合: プロトコルは各コンポーネント内ではなく、アプリケーションの起動時に一度だけ登録してください。これにより、マップがマウントされる前に MapLibre がハンドラーを利用できます。たとえば、ルートレベルのエフェクト内、またはマッププロバイダーの初期化時に maplibregl.addProtocol('pmtiles', protocol.tile) を呼び出します。最後のマップがアンマウントされるとき(またはアプリが終了するとき)に maplibregl.removeProtocol('pmtiles') を呼び出して、リークを防いでください。React 向けのセットアップについては、MapLibre GL での PMTiles(Protomaps)をご覧ください。
PMTiles のホスティング
ファイルを提供し、HTTP Range リクエストに対応しているホストであれば使用できます。
- AWS S3 — パブリック読み取り(または署名付き URL)を有効にします。S3 は Range に対応しています。
Cache-Controlを設定し、必要に応じて CloudFront を使用します。 - Cloudflare R2 — S3 互換です。パブリックアクセスを有効にするか、署名付き URL を使用します。キャッシュのため、Cloudflare の背後に配置します。
- GitHub Pages — ファイルサイズが 100 MB 未満であれば、MapLibre GL JS は同じリポジトリ内の .pmtiles ファイルからタイルを読み込めます。
- Netlify / Vercel — .pmtiles ファイルをアップロードします。通常、静的ホスティングは Range に対応しています。各プロバイダーのファイルサイズ制限を確認してください。
- 任意の静的ホスト — サーバーが
Accept-Ranges: bytesを返し、Rangeヘッダーに正しく応答することを確認してください。
CORS: ブラウザーは PMTiles の URL に対してクロスオリジンリクエストを送信します。ホストは Access-Control-Allow-Origin: *(または自分のドメイン)と Access-Control-Allow-Headers: Range(またはすべてのヘッダーの許可)を返す必要があります。そうでない場合、MapLibre はタイルを読み込めません。
キャッシュヘッダー: パフォーマンスを向上させるには、.pmtiles ファイルのキャッシュ期間を長く設定します(ファイルが不変であれば、例:Cache-Control: public, max-age=31536000)。CDN は Range レスポンスをキャッシュします。
PMTiles CLI
pmtiles CLI は、PMTiles を扱うための公式コマンドラインツールです(変換には MBTiles も使用します)。実行時依存関係のない単一のバイナリで、ダウンロードして実行できます。
インストールして使用する理由:
- MBTiles を PMTiles に変換 — 多くのツール(tippecanoe、GDAL、martin-cp)は MBTiles を出力します。1 つのコマンドで任意の .mbtiles ファイルを .pmtiles ファイルに変換できます:
pmtiles convert in.mbtiles out.pmtiles。パイプラインがすでに MBTiles を生成している場合、これが PMTiles を取得する最も簡単な方法であることがよくあります。 - アーカイブの検査と検証 —
pmtiles show <file>はヘッダーとメタデータ(境界、ズーム範囲、タイル数)を表示します。pmtiles verify <file>はアーカイブの整合性を確認します。デバッグやアップロード前のファイル確認に便利です。 - 一部の抽出 —
pmtiles extractは既存のアーカイブから小さな .pmtiles ファイルを作成します(例:バウンディングボックスまたはズーム範囲を指定)。これにより、ソースから再生成せずに、特定の地域や限定したズーム範囲のデータを提供できます。
❌ サブコマンドの一覧は固定されています — ありそうな名前の動詞を思いつきで使わないでください。 go-pmtiles に含まれるコマンドは show、tile、verify、extract、merge、serve、convert、cluster、upload、edit、version のみです。info コマンドも inspect コマンドもありません。また、edit 以外にコマンドラインからメタデータを設定するコマンドはありません。アーカイブのヘッダー、境界、ズーム範囲を読み取るコマンドは pmtiles show、整合性を確認するコマンドは pmtiles verify です。
インストール: 使用する OS/アーキテクチャに対応したバイナリを GitHub Releases(go-pmtiles) からダウンロードするか、Docker の protomaps/go-pmtiles を使用します。
できないこと: CLI が扱えるのはタイルアーカイブ(MBTiles と PMTiles)のみです。GeoJSON、Shapefile、OSM、その他のソース形式は読み込めません。これらの形式から PMTiles を作成するには、タイルを生成するツール(下記の PMTiles の生成 を参照)を使用し、そのツールが MBTiles を出力する場合は pmtiles convert を実行して PMTiles に変換します。
PMTiles の生成
2 つの方法があります: (1)変換 — PMTiles CLI は MBTiles ↔ PMTiles の変換のみを行います。GeoJSON、Shapefile、OSM、その他のソース形式は読み込みません。(2)ソースデータから生成 — tippecanoe、Planetiler、GDAL 経由の ogr2ogr などのツールは、多様なファイル形式やデータベースから読み込み、ベクタータイル(PMTiles または MBTiles)を生成します。MBTiles が出力された場合は、pmtiles convert を使って PMTiles に変換してください。
PMTiles CLI(変換のみ:MBTiles ↔ PMTiles)
インストールする理由やその他のコマンド(show、verify、extract)については、上記の PMTiles CLI を参照してください。MBTiles を PMTiles に変換するには:
pmtiles convert input.mbtiles output.pmtiles
以下のツールは、ソースデータ(GeoJSON、OSM、Shapefile、PostGIS など)からタイルを生成します。PMTiles または MBTiles を出力します。MBTiles が出力された場合は、pmtiles convert を実行して PMTiles に変換してください。
Planetiler(OSM/OpenMapTiles スキーマ)
Planetiler は OpenStreetMap(またはその他のソース)を読み込み、OpenMapTiles スキーマの PMTiles または MBTiles を出力します。
# Example: download a region's OSM extract and build a PMTiles file from it
java -jar planetiler.jar --download --area=monaco --output=monaco.pmtiles
エリア名、カスタムソース、スキーマオプションについては Planetiler のドキュメントを参照してください。出力は単一の .pmtiles ファイルなので、S3/R2/静的ホストにアップロードできます。
tippecanoe
tippecanoe は、ソース形式(GeoJSON、FlatGeobuf、CSV)からベクタータイルを生成します。v2.17 以降は、PMTiles を直接出力できます(-o output.pmtiles)。MBTiles を出力して、pmtiles convert で変換することもできます。
# Direct PMTiles output (v2.17+)
tippecanoe -zg -o output.pmtiles input.geojson
# Or MBTiles then convert: tippecanoe -o output.mbtiles -z 14 input.geojson && pmtiles convert output.mbtiles output.pmtiles
ogr2ogr(GDAL)
GDAL の ogr2ogr は、さまざまな地理空間形式(Shapefile、PostGIS、GeoJSON など)からタイルを生成し、MBTiles または PMTiles(GDAL 3.8 以降)を書き出せます。小規模なデータセットに最適です。大規模なベクタータイルセットでは、tippecanoe のほうが効率的です。
ラスターおよび raster-dem PMTiles
PMTiles はラスタータイル(PNG/JPEG。衛星画像やレンダリング済み画像など)と、raster-dem(標高/地形データ。Terrarium または Mapbox エンコーディングなど)に対応しています。ラスターまたは raster-dem の PMTiles を生成するツールを使用してください。同じプロトコルとホスティング方法を適用できます。スタイルでは、画像に type: 'raster'、地形に "encoding": "terrarium"(または "mapbox")を指定した type: 'raster-dem' を使ってください。例については、上記の MapLibre Integration を参照してください。
Overture Maps
Overture Maps は、世界規模のオープンな地図データを公開しています。一部のプロバイダーは、Overture 由来のデータを PMTiles として配布しています(建物、場所、交通データなど)。Planetiler やその他のパイプラインを使って、Overture データから PMTiles を構築することもできます。上記のように、MapLibre のスタイルで PMTiles の URL を使用してください。
パフォーマンスのヒント
- CDN — .pmtiles ファイルを CDN(CloudFront、Cloudflare)から配信すると、範囲リクエストを世界中で高速に処理できます。
- 圧縮 — PMTiles はタイルを圧縮して保存します。ライブラリが解凍を処理します。範囲リクエストを妨げる方法で、サーバーがファイル全体を二重に圧縮(gzip など)しないようにしてください。
- 複数ファイル — 対象範囲が非常に広い場合は、地域ごとに複数の .pmtiles ファイルに分割し、ソース URL を切り替えるか、範囲ごとに複数のソースを使用してください。
- キャッシュ — ファイルに強力なキャッシュヘッダーを設定してください。ブラウザーと CDN が範囲レスポンスをキャッシュします。
関連スキル
- maplibre-tile-sources — データセットに GeoJSON とタイルのどちらを選ぶか。
- maplibre-source-wiring — TileJSON、
source-layer、グリフとスプライト、CORS。 - maplibre-style-patterns — ベクターソース(PMTiles をバックエンドとするソースを含む)のレイヤーとペイントの設定。(リポジトリにはまだありません。)
参考資料
- MapLibre GL JS:PMTiles のソースとプロトコル — プロトコル、ベクターソース、ラスターソースを追加する公式の例です。
- MapLibre GL 用 PMTiles(Protomaps)— セットアップ、ベクター/ラスター/ラスター DEM(Terrarium)ソース、React の使用方法です。
addProtocol(MapLibre GL JS API) — カスタムプロトコルハンドラーのシグネチャと、{data}を返す形式です。- PMTiles — フォーマットとプロトコル
- pmtiles CLI — PMTiles を作成する最も簡単な方法(
convert、show、verify、extract) - Planetiler — OSM → PMTiles/MBTiles
- MapLibre GL JS — スタイル仕様と API
このスキルはスナップショットです。 一次情報(上記の参考資料、MapLibre の現行ドキュメント、または MapLibre の実行時の動作)と矛盾する場合は、一次情報を優先してください。それに従ったうえで、情報源と MapLibre のバージョンを明記して不一致を報告してください。インストール済みのコピーを編集しても誰の役にも立たず、次回の更新で上書きされます。