npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@makina-corpus/maplibre-offline-pmtiles

v2.1.1

Published

A plugin for MapLibre GL JS to manage offline maps in PMTiles format.

Downloads

54

Readme

MapLibre Offline PMTiles

A plugin for MapLibre GL JS to manage offline maps in PMTiles format.

This project provides a set of functions to help manage offline maps, allowing you to download, store (via OPFS - Origin Private File System), and render vector and raster maps without an internet connection.

Features

  • 📥 Download PMTiles files.
  • 💾 Optimized storage using OPFS.
  • 🗺️ Seamless integration with MapLibre (custom protocol offline-pmtiles://).
  • 🗜️ Support for both MVT (Mapbox Vector Tile) and MLT (MapLibre Tile) formats.
  • 📊 Storage quota management.

Installation

npm install @makina-corpus/maplibre-offline-pmtiles

Usage

Initialization

import maplibregl from 'maplibre-gl';
import { OfflinePlugin, OFFLINE_STATUS } from '@makina-corpus/maplibre-offline-pmtiles';

// 1. Register the offline protocol
OfflinePlugin.registerProtocol(maplibregl);

// 2. Initialize the plugin
const offlinePlugin = new OfflinePlugin();

// 3. Example: Download a map
await offlinePlugin.downloadMap(
    'https://example.com/map.pmtiles',
    'my-map',
    (status) => console.log('Download status:', status)
);

// 4. Instantiate MapLibre
const map = new maplibregl.Map({
    container: 'map',
    style: {
        version: 8,
        sources: {},
        layers: []
    }
});

// 5. Load the map and its offline style automatically once MapLibre is ready
map.on('load', async () => {
    // This will automatically add the source and any saved custom style layers
    await offlinePlugin.loadMap(map, 'my-map');
});

// Alternatively, you can always manually add the source using the special protocol:
// map.addSource('my-offline-source', {
//     type: 'vector', // or 'raster'
//     url: 'offline-pmtiles://my-map'
// });

Development

# Install dependencies
npm install

# Run the development example
npm run dev

# Build the library
npm run build

# Build the example (PWA)
npm run build:example

# Preview the production build of the example
npm run preview

API Reference

Best Practices & Storage Limits (for PWA / Mobile)

This plugin relies on the browser's OPFS (Origin Private File System) to store PMTiles files. OPFS completely changes the game compared to IndexedDB: it offers excellent, near-native performance for parsing and storing very large files without significant memory overhead.

While modern browsers have generous storage quotas (often >1GB based on free disk space), you should still carefully manage the size of the maps you provide for offline use. Although the browser can handle massive files, downloading them over a mobile network remains a bottleneck.

Recommendations:

  • Network Constraints: While OPFS can easily read a 500MB .pmtiles file instantly, downloading it over 3G/4G can fail or take a long time. A good rule of thumb for reliable mobile downloads is to keep files between 10MB and 100MB.
  • Avoid entire countries: Do not force mobile users to download hundreds of megabytes (like an entire country) over slow or metered cellular networks. Instead, provide PMTiles extracts at the regional, city, or district level.
  • Limit Zoom Levels: Only package the zoom levels you actually need (e.g., zoom 10 to 15). Zoom levels 14 and 15 contain the most data and drastically increase file size.
  • Quota Exceeded: The plugin detects storage limits and will emit an OFFLINE_STATUS.ERROR_QUOTA progress event if the device runs out of allocated space. Always handle this status in your UI.

Handling Offline Styles (Sprites and Fonts)

The plugin downloads PMTiles data (map geometries) and optionally caches the associated style.json in OPFS. However, MapLibre fetches external style resources like Sprites (icons) and Glyphs (fonts) dynamically. The plugin does not intercept or store these assets.

To ensure your map remains fully functional offline (displaying text labels and icons), you should delegate the caching of these assets to your Progressive Web App (PWA) Service Worker:

Local Assets (Recommended): Download the necessary font .pbf folders and sprite files locally into your application's public/ or assets/ directory. Update the sprite and glyphs URLs in your style.json to point to these relative paths. Your Service Worker will then cache them automatically before going offline, during the initial installation of your app. This guarantees 100% availability.

OfflinePlugin

The main class for managing offline maps.

static registerProtocol(maplibregl)

Registers the offline-pmtiles protocol with MapLibre GL JS. MUST be called before using the plugin.

  • maplibregl: The MapLibre GL JS object.

constructor()

Creates a new instance of the plugin.

async downloadMap(url, name, onProgress, styleSource, options)

Downloads a PMTiles file and saves it to local storage.

  • url (string): URL of the PMTiles file.
  • name (string): Unique ID/name for the map.
  • onProgress (function): Callback ({ code, message, progress }). See OFFLINE_STATUS below.
  • styleSource (string|object): (Optional) URL to a style JSON or the style object itself.
  • options (object): (Optional) Download options.
    • signal (AbortSignal): An instance of AbortSignal to cancel the download and clean up storage.

Example with cancellation:

const controller = new AbortController();

try {
    await offlinePlugin.downloadMap(
        'https://example.com/map.pmtiles',
        'my-map',
        (p) => console.log(p.progress),
        null,
        { signal: controller.signal }
    );
} catch (e) {
    if (e.name === 'AbortError') {
        console.log('Download cancelled and files cleaned up');
    }
}

// Later...
controller.abort();

async loadMap(map, name, onProgress)

Loads a map from storage into the MapLibre instance.

  • map (MapLibreMap): The map instance.
  • name (string): Name of the map to load.
  • onProgress (function): Callback for status updates. See OFFLINE_STATUS.

unloadMap(map, name)

Removes the map's layers and source from the map instance, but keeps files in storage.

  • map (MapLibreMap): The map instance.
  • name (string): Name of the map to unload.

async removeMap(map, name, onProgress)

Permanently deletes the map (and style) from storage and removes it from the map instance.

  • map (MapLibreMap): The map instance.
  • name (string): Name of the map to delete.
  • onProgress (function): Callback for status updates. See OFFLINE_STATUS.

toggleMap(map, name, visible)

Toggles the visibility of all layers associated with the map.

  • map (MapLibreMap): The map instance.
  • name (string): Name of the map.
  • visible (boolean): true to show, false to hide.

async getStorageUsage()

Returns estimated storage usage.

  • Returns: Promise<{used: number, quota: number, percent: number}> or null.

OFFLINE_STATUS

Enum constants corresponding to the code property in the onProgress callback object.

  • START: Download has initiated.
  • PROGRESS: Download is in progress.
  • COMPLETE: Download completed successfully.
  • ERROR: A general error occurred during download.
  • ERROR_QUOTA: Storage quota exceeded (browser limit reached).

License

MIT