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

map-gl-offline

v0.8.2

Published

A TypeScript-compatible npm package for MapLibre GL JS that enables comprehensive offline storage and usage of vector/raster tiles, sprites, styles, fonts (glyphs), and entire map regions with advanced analytics, import/export capabilities, and intelligen

Readme

Map GL Offline 🗺️

npm version License: MIT TypeScript

📖 Documentation · 🎮 Live Demo · 🐛 Issues

TypeScript offline-map library for MapLibre GL JS and Mapbox GL JS. Download styles, tiles, sprites, glyphs, and fonts to IndexedDB; load them back with zero network. Ships with a glassmorphic UI control and a complete programmatic API.

Map GL Offline Demo

Features

  • 🗺️ Offline regions — polygon selection, smart tile management, extra vector/raster overlays
  • 🎨 Full resource capture — styles, sprites, fonts, glyphs with Unicode ranges
  • 🔗 Mapbox GL + MapLibre GL — auto-detection, mapbox:// URL resolution, Standard style with 3D/terrain
  • 📊 Analytics & cleanup — storage reports, auto-cleanup, quota-aware downloads
  • 🎨 UI control — glassmorphic panel, dark/light themes, English/Arabic (RTL), polygon drawing
  • 🛠️ Programmatic APIdownloadRegion with per-phase progress, full TypeScript types

Install

npm install map-gl-offline

Or via CDN as the mapgloffline global:

<script src="https://unpkg.com/map-gl-offline/dist/index.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/map-gl-offline/style.css" />

Quick Start

MapLibre GL JS

import maplibregl from 'maplibre-gl';
import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';
import 'maplibre-gl/dist/maplibre-gl.css';
import 'map-gl-offline/style.css';

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
  center: [-74.006, 40.7128],
  zoom: 12,
});

const offlineManager = new OfflineMapManager();

map.on('load', () => {
  map.addControl(
    new OfflineManagerControl(offlineManager, {
      styleUrl: map.getStyle().sprite,
      mapLib: maplibregl, // enables idb:// protocol
    }),
    'top-right',
  );
});

Mapbox GL JS

Mapbox GL JS v3 lacks addProtocol, so the library uses a Service Worker. Run one of:

npx map-gl-offline init            # CLI (recommended)
# or add to vite.config.js:
# import { offlineSwPlugin } from 'map-gl-offline/vite-plugin';
# plugins: [offlineSwPlugin()]
# or manually: cp node_modules/map-gl-offline/dist/idb-offline-sw.js public/

Then:

import mapboxgl from 'mapbox-gl';
import { OfflineMapManager, OfflineManagerControl } from 'map-gl-offline';

mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/standard',
  center: [-74.006, 40.7128],
  zoom: 12,
});

const offlineManager = new OfflineMapManager();
map.on('load', () =>
  map.addControl(
    new OfflineManagerControl(offlineManager, {
      styleUrl: 'mapbox://styles/mapbox/standard',
      accessToken: mapboxgl.accessToken,
    }),
    'top-right',
  ),
);

Programmatic Usage

downloadRegion runs the full pipeline (style → sprites → glyphs → tiles → metadata) with per-phase progress. addRegion alone only stores metadata — use downloadRegion to actually fetch assets.

import { OfflineMapManager } from 'map-gl-offline';

const offlineManager = new OfflineMapManager();

await offlineManager.downloadRegion(
  {
    id: 'downtown',
    name: 'Downtown',
    bounds: [[-74.0559, 40.7128], [-74.0059, 40.7628]],
    minZoom: 10,
    maxZoom: 16,
    styleUrl: 'https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY',
  },
  {
    onProgress: ({ phase, percentage, message }) => {
      console.log(`[${phase}] ${percentage.toFixed(1)}% ${message ?? ''}`);
    },
  },
);

// Manage
await offlineManager.listStoredRegions();
await offlineManager.getStoredRegion('downtown');
await offlineManager.deleteRegion('downtown');

// Analytics & cleanup
await offlineManager.getComprehensiveStorageAnalytics();
await offlineManager.cleanupExpiredRegions();
await offlineManager.setupAutoCleanup({ intervalHours: 24, maxAge: 30 });

Sparse-source detection

For composite styles (e.g. Mapbox Standard) that reference sparse tilesets like indoor-v3 or landmark-pois-v1, the tile downloader probes start/middle/end tiles per source and drops any that return majority-404. Disable with tileOptions: { probeSourcesBeforeDownload: false }.

Recovering from an incompatible DB

If another app on the same origin has created offline-map-db at a newer version, dbPromise throws a typed error. Offer a reset UX:

import { dbPromise, OfflineMapDBVersionError, resetOfflineMapDB } from 'map-gl-offline';

try {
  await dbPromise;
} catch (err) {
  if (err instanceof OfflineMapDBVersionError) {
    if (confirm('Offline storage is incompatible. Clear it?')) {
      await resetOfflineMapDB(); // destructive
      location.reload();
    }
  }
}

Upgrading from 0.5.x? Read the 0.6.0 migration guide — covers the rename of ResourceService.getXxxStatisticsgetXxxStats, the addRegion vs downloadRegion split, and the expiry timestamp fix.

API at a glance

  • RegionsdownloadRegion, loadRegion, addRegion, getStoredRegion, listStoredRegions, listRegions, deleteRegion
  • AnalyticsgetComprehensiveStorageAnalytics, getRegionAnalytics, getTileStats, getFontStats, getSpriteStats, getGlyphStats
  • CleanupcleanupExpiredRegions, performSmartCleanup, cleanupOld{Fonts,Sprites,Glyphs}, verifyAndRepair{Fonts,Sprites,Glyphs}, setupAutoCleanup, performCompleteMaintenance
  • Import / ExportexportRegionAsMBTiles, importRegion, downloadExportedRegion (binary SQLite MBTiles, QGIS/tippecanoe-compatible)
  • Storage utilitiesdbPromise, OfflineMapDBVersionError, resetOfflineMapDB, loadAllStoredRegions, resourceKeyBelongsToStyle

See the full API reference and examples for every option and pattern.

Browser compatibility

Chrome 51+ · Firefox 45+ · Safari 10+ · Edge 79+ · modern mobile browsers. Requires IndexedDB and ES2015+.

Contributing

git clone https://github.com/muimsd/map-gl-offline.git
cd map-gl-offline && npm install
npm run dev          # dev harness
npm test             # unit tests
npm run build        # library

Issues and PRs welcome. See CHANGELOG.md for release notes.

License

MIT © Muhammad Imran Siddique


📖 Docs · 🎮 Demo · ⭐ GitHub