{"_id":"@acalcutt/maplibre-contour-pmtiles","_rev":"4-c14126a01b5b32ba163f4ebb498ba993","name":"@acalcutt/maplibre-contour-pmtiles","dist-tags":{"latest":"0.1.2"},"versions":{"0.0.1":{"name":"@acalcutt/maplibre-contour-pmtiles","version":"0.0.1","author":{"name":"Michael Barry"},"license":"BSD-3-Clause","_id":"@acalcutt/maplibre-contour-pmtiles@0.0.1","maintainers":[{"name":"acalcutt","email":"acalcutt@techidiots.net"}],"homepage":"https://github.com/onthegomap/maplibre-contour","bugs":{"url":"https://github.com/onthegomap/maplibre-contour/issues"},"dist":{"shasum":"27c5ca3bfe280cc2ecba39ec28854ae2a7f157e3","tarball":"https://registry.npmjs.org/@acalcutt/maplibre-contour-pmtiles/-/maplibre-contour-pmtiles-0.0.1.tgz","fileCount":66,"integrity":"sha512-YLFjIKcJ8IRaDUOidime4loNi5Bh1YEqw4iAURVS1NTl0iLbN+B3QamiT3XnccLY564bPNEIJI0W4bcFphwvNA==","signatures":[{"sig":"MEUCIQCJ1HXg/LNjFSQrAq3eWTABIuxOKSBwJk/y+ZhHyRrS6gIge1m3b3dGi/Hc+0v2M5MJ1+aZ/4C4HE9hb4t0z1cjODc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":656302},"main":"dist/maplibre-contour-pmtiles.cjs","type":"module","types":"dist/index.d.ts","unpkg":"dist/maplibre-contour-pmtiles.min.js","module":"dist/maplibre-contour-pmtiles.mjs","exports":{"types":"./dist/index.d.ts","module":"./dist/maplibre-contour-pmtiles.mjs","browser":"./dist/maplibre-contour-pmtiles.min.js","require":"./dist/maplibre-contour-pmtiles.cjs"},"gitHead":"b35ff0c69d0df935873ec5179175a525be908d80","scripts":{"jest":"jest","lint":"eslint src","test":"run-p typecheck lint jest checkformat","bench":"npm run build && node benchmark.js","build":"rm -rf dist && cross-env NODE_ENV=web rollup -c && npm run generate-types && tsc --project tsconfig.dist.json","format":"prettier src --write","typecheck":"tsc --noEmit","jest:watch":"jest --watch","test-build":"cd test-project && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","checkformat":"prettier src --check","test-build-v3":"cd test-project-maplibre-3 && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","generate-types":"tsc --emitDeclarationOnly --declaration --outDir dist && rm -rf dist/*{.t,-j}est.d.ts","prepublishOnly":"npm run test && npm run build"},"_npmUser":{"name":"acalcutt","email":"acalcutt@techidiots.net"},"repository":{"url":"git+https://github.com/onthegomap/maplibre-contour.git","type":"git"},"_npmVersion":"10.2.3","description":"Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources","directories":{},"_nodeVersion":"20.10.0","_hasShrinkwrap":false,"devDependencies":{"pbf":"4.0.1","jest":"29.7.0","pngjs":"7.0.0","canvas":"^2.11.2","eslint":"9.16.0","lodash":"4.17.21","rollup":"4.28.1","pmtiles":"^4.1.0","ts-jest":"29.2.5","prettier":"3.4.2","benchmark":"2.1.4","cross-env":"^7.0.3","@eslint/js":"9.17.0","@types/pbf":"3.0.5","typescript":"5.7.2","@types/jest":"29.5.14","@types/node":"22.10.2","npm-run-all":"4.1.5","@types/pngjs":"6.0.5","whatwg-fetch":"3.6.20","@types/lodash":"4.17.13","@eslint/eslintrc":"3.2.0","@mapbox/tilebelt":"^2.0.2","@types/benchmark":"2.1.5","typescript-eslint":"8.18.0","@mapbox/vector-tile":"2.0.3","@rollup/plugin-alias":"^5.1.1","@rollup/plugin-terser":"0.4.4","@rollup/plugin-replace":"^6.0.2","eslint-config-prettier":"9.1.0","jest-environment-jsdom":"29.7.0","@rollup/plugin-commonjs":"28.0.2","@rollup/plugin-typescript":"12.1.2","@types/mapbox__vector-tile":"1.3.4","@rollup/plugin-node-resolve":"16.0.0"},"_npmOperationalInternal":{"tmp":"tmp/maplibre-contour-pmtiles_0.0.1_1735760893081_0.7067358047847665","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@acalcutt/maplibre-contour-pmtiles","version":"0.1.0","author":{"name":"Michael Barry"},"license":"BSD-3-Clause","_id":"@acalcutt/maplibre-contour-pmtiles@0.1.0","maintainers":[{"name":"acalcutt","email":"acalcutt@techidiots.net"}],"homepage":"https://github.com/onthegomap/maplibre-contour","bugs":{"url":"https://github.com/onthegomap/maplibre-contour/issues"},"dist":{"shasum":"a87e273799ea17fbf06fc5903f4feada1ac537ba","tarball":"https://registry.npmjs.org/@acalcutt/maplibre-contour-pmtiles/-/maplibre-contour-pmtiles-0.1.0.tgz","fileCount":66,"integrity":"sha512-SW2xbPZh87j3j81A+dBMw3k7GNAlAeIivqE77r4uANb+Aew9nHSpMlP7Nc0UUjaSSBsZPBF2AowzSN2ooumR0A==","signatures":[{"sig":"MEUCIEwJz5//LaR9Y3kU206KZg9hHRvYMt/VifIPQy+LtjRQAiEApmJkOjo58CGcAuMcQ0h9FDB5tLodF3HQFexl7+jUMZo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":665313},"main":"dist/maplibre-contour-pmtiles.cjs","type":"module","types":"dist/index.d.ts","unpkg":"dist/maplibre-contour-pmtiles.min.js","module":"dist/maplibre-contour-pmtiles.mjs","exports":{"types":"./dist/index.d.ts","module":"./dist/maplibre-contour-pmtiles.mjs","browser":"./dist/maplibre-contour-pmtiles.min.js","require":"./dist/maplibre-contour-pmtiles.cjs"},"gitHead":"01a8a3bf52ee798b2735000bb0fb80c69ab5b656","scripts":{"jest":"jest","lint":"eslint src","test":"run-p typecheck lint jest checkformat","bench":"npm run build && node benchmark.js","build":"rm -rf dist && cross-env NODE_ENV=web rollup -c && npm run generate-types && tsc --project tsconfig.dist.json","format":"prettier src --write","typecheck":"tsc --noEmit","jest:watch":"jest --watch","test-build":"cd test-project && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","checkformat":"prettier src --check","test-build-v3":"cd test-project-maplibre-3 && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","generate-types":"tsc --emitDeclarationOnly --declaration --outDir dist && rm -rf dist/*{.t,-j}est.d.ts","prepublishOnly":"npm run test && npm run build"},"_npmUser":{"name":"acalcutt","email":"acalcutt@techidiots.net"},"repository":{"url":"git+https://github.com/onthegomap/maplibre-contour.git","type":"git"},"_npmVersion":"10.2.3","description":"Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources","directories":{},"_nodeVersion":"20.10.0","_hasShrinkwrap":false,"devDependencies":{"pbf":"4.0.1","jest":"29.7.0","pngjs":"7.0.0","sharp":"^0.33.5","tslib":"^2.8.1","canvas":"^2.11.2","eslint":"9.17.0","lodash":"4.17.21","rollup":"4.28.1","pmtiles":"^4.1.0","ts-jest":"29.2.5","prettier":"3.4.2","benchmark":"2.1.4","commander":"^13.0.0","cross-env":"^7.0.3","@eslint/js":"9.17.0","@types/pbf":"3.0.5","typescript":"5.7.2","@types/jest":"29.5.14","@types/node":"22.10.2","npm-run-all":"4.1.5","@types/pngjs":"6.0.5","whatwg-fetch":"3.6.20","@types/lodash":"4.17.13","@eslint/eslintrc":"3.2.0","@mapbox/tilebelt":"^2.0.2","@types/benchmark":"2.1.5","typescript-eslint":"8.18.2","@mapbox/vector-tile":"2.0.3","@rollup/plugin-alias":"^5.1.1","@rollup/plugin-terser":"0.4.4","@rollup/plugin-replace":"^6.0.2","eslint-config-prettier":"9.1.0","jest-environment-jsdom":"29.7.0","@rollup/plugin-commonjs":"28.0.2","@rollup/plugin-typescript":"12.1.2","@types/mapbox__vector-tile":"1.3.4","@rollup/plugin-node-resolve":"16.0.0"},"_npmOperationalInternal":{"tmp":"tmp/maplibre-contour-pmtiles_0.1.0_1735803158959_0.9720384367669843","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@acalcutt/maplibre-contour-pmtiles","version":"0.1.1","author":{"name":"Michael Barry"},"license":"BSD-3-Clause","_id":"@acalcutt/maplibre-contour-pmtiles@0.1.1","maintainers":[{"name":"acalcutt","email":"acalcutt@techidiots.net"}],"homepage":"https://github.com/onthegomap/maplibre-contour","bugs":{"url":"https://github.com/onthegomap/maplibre-contour/issues"},"dist":{"shasum":"0eecdcb997776b4453df98686958c7400688a773","tarball":"https://registry.npmjs.org/@acalcutt/maplibre-contour-pmtiles/-/maplibre-contour-pmtiles-0.1.1.tgz","fileCount":66,"integrity":"sha512-Jq150cGIXAwbL1XVlN2saNnnDgAAlJVXGf8FF/ytp3fqrEFIzWBQ89Qn2fL6LG+S9wqK22KB3Z2/g/WscAi6CQ==","signatures":[{"sig":"MEUCIAMw/gJpQXuYl+O3JCJ3eeE1MMJPrRto9uunD448r+0VAiEAys14NvdlAf4bGlMwnwOETYYTj0HxckomKTTx276VSpc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":670980},"main":"dist/maplibre-contour-pmtiles.cjs","type":"module","types":"dist/index.d.ts","unpkg":"dist/maplibre-contour-pmtiles.min.js","module":"dist/maplibre-contour-pmtiles.mjs","exports":{"types":"./dist/index.d.ts","module":"./dist/maplibre-contour-pmtiles.mjs","browser":"./dist/maplibre-contour-pmtiles.min.js","require":"./dist/maplibre-contour-pmtiles.cjs"},"gitHead":"0b834e7c22b71e6cb533a57add4f3fbf294e8ab6","scripts":{"jest":"jest","lint":"eslint src","test":"run-p typecheck lint jest checkformat","bench":"npm run build && node benchmark.js","build":"rm -rf dist && cross-env NODE_ENV=web rollup -c && npm run generate-types && tsc --project tsconfig.dist.json","format":"prettier src --write","typecheck":"tsc --noEmit","jest:watch":"jest --watch","test-build":"cd test-project && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","checkformat":"prettier src --check","test-build-v3":"cd test-project-maplibre-3 && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","generate-types":"tsc --emitDeclarationOnly --declaration --outDir dist && rm -rf dist/*{.t,-j}est.d.ts","prepublishOnly":"npm run test && npm run build"},"_npmUser":{"name":"acalcutt","email":"acalcutt@techidiots.net"},"repository":{"url":"git+https://github.com/onthegomap/maplibre-contour.git","type":"git"},"_npmVersion":"10.2.3","description":"Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources","directories":{},"_nodeVersion":"20.10.0","_hasShrinkwrap":false,"devDependencies":{"pbf":"4.0.1","jest":"29.7.0","pngjs":"7.0.0","sharp":"^0.33.5","tslib":"^2.8.1","canvas":"^2.11.2","eslint":"9.17.0","lodash":"4.17.21","rollup":"4.28.1","pmtiles":"^4.1.0","ts-jest":"29.2.5","prettier":"3.4.2","benchmark":"2.1.4","commander":"^13.0.0","cross-env":"^7.0.3","@eslint/js":"9.17.0","@types/pbf":"3.0.5","typescript":"5.7.2","@types/jest":"29.5.14","@types/node":"22.10.2","npm-run-all":"4.1.5","@types/pngjs":"6.0.5","whatwg-fetch":"3.6.20","@types/lodash":"4.17.13","@eslint/eslintrc":"3.2.0","@mapbox/tilebelt":"^2.0.2","@types/benchmark":"2.1.5","typescript-eslint":"8.18.2","@mapbox/vector-tile":"2.0.3","@rollup/plugin-alias":"^5.1.1","@rollup/plugin-terser":"0.4.4","@rollup/plugin-replace":"^6.0.2","eslint-config-prettier":"9.1.0","jest-environment-jsdom":"29.7.0","@rollup/plugin-commonjs":"28.0.2","@rollup/plugin-typescript":"12.1.2","@types/mapbox__vector-tile":"1.3.4","@rollup/plugin-node-resolve":"16.0.0"},"_npmOperationalInternal":{"tmp":"tmp/maplibre-contour-pmtiles_0.1.1_1735839705902_0.5121890344863513","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@acalcutt/maplibre-contour-pmtiles","version":"0.1.2","description":"Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources","unpkg":"dist/maplibre-contour-pmtiles.min.js","main":"dist/maplibre-contour-pmtiles.cjs","module":"dist/maplibre-contour-pmtiles.mjs","types":"dist/index.d.ts","exports":{"module":"./dist/maplibre-contour-pmtiles.mjs","require":"./dist/maplibre-contour-pmtiles.cjs","types":"./dist/index.d.ts","browser":"./dist/maplibre-contour-pmtiles.min.js"},"scripts":{"bench":"npm run build && node benchmark.js","build":"rm -rf dist && cross-env NODE_ENV=web rollup -c && npm run generate-types && tsc --project tsconfig.dist.json","test-build-v3":"cd test-project-maplibre-3 && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","test-build":"cd test-project && rm -rf node_modules && rm -rf package-lock.json && npm i && npm test","generate-types":"tsc --emitDeclarationOnly --declaration --outDir dist && rm -rf dist/*{.t,-j}est.d.ts","jest":"jest","jest:watch":"jest --watch","test":"run-p typecheck lint jest checkformat","lint":"eslint src","format":"prettier src --write","checkformat":"prettier src --check","typecheck":"tsc --noEmit","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/acalcutt/maplibre-contour-pmtiles.git"},"type":"module","author":{"name":"Michael Barry/Andrew Calcutt"},"license":"BSD-3-Clause","homepage":"https://github.com/acalcutt/maplibre-contour-pmtiles.git","devDependencies":{"@eslint/eslintrc":"3.2.0","@eslint/js":"9.18.0","@mapbox/tilebelt":"^2.0.2","@mapbox/vector-tile":"2.0.3","@rollup/plugin-alias":"^5.1.1","@rollup/plugin-commonjs":"28.0.2","@rollup/plugin-node-resolve":"16.0.1","@rollup/plugin-replace":"^6.0.2","@rollup/plugin-terser":"0.4.4","@rollup/plugin-typescript":"12.1.2","@types/benchmark":"2.1.5","@types/jest":"29.5.14","@types/lodash":"4.17.20","@types/mapbox__vector-tile":"1.3.4","@types/node":"22.10.7","@types/pbf":"3.0.5","@types/pngjs":"6.0.5","benchmark":"2.1.4","canvas":"3.2.0","commander":"14.0.0","cross-env":"^7.0.3","eslint":"9.35.0","eslint-config-prettier":"10.0.1","jest":"29.7.0","jest-environment-jsdom":"30.1.2","lodash":"4.17.21","npm-run-all":"4.1.5","pbf":"4.0.1","pmtiles":"^4.1.0","pngjs":"7.0.0","prettier":"3.5.3","rollup":"4.39.0","sharp":"0.34.3","ts-jest":"29.2.5","tslib":"^2.8.1","typescript":"5.7.3","typescript-eslint":"8.42.0","whatwg-fetch":"3.6.20"},"_id":"@acalcutt/maplibre-contour-pmtiles@0.1.2","gitHead":"911f00060f1271e1050c0bb296d1edf1c4f8e324","bugs":{"url":"https://github.com/acalcutt/maplibre-contour-pmtiles/issues"},"_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-dCyJFLLM4NomLoJ22McRp7yETFmzUuA6iEMVJS6+mFyHoNk7Sv6RI4Hn0DhGKeyjcJgan3YnfSnzsqRinnXSug==","shasum":"037f06ff89ad8e4abaa89fedb8dc33d9181c209a","tarball":"https://registry.npmjs.org/@acalcutt/maplibre-contour-pmtiles/-/maplibre-contour-pmtiles-0.1.2.tgz","fileCount":66,"unpackedSize":671793,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCufhvFquX1BZ/GEAiJyfOJPs5QNp0UOG2Ibs5hhFM2cgIgRsvyR4WQMeosHhGgT4VvN6pRwBXVhHYF0claQDfNr7I="}]},"_npmUser":{"name":"acalcutt","email":"acalcutt@techidiots.net"},"directories":{},"maintainers":[{"name":"acalcutt","email":"acalcutt@techidiots.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/maplibre-contour-pmtiles_0.1.2_1757423929848_0.581434842941045"},"_hasShrinkwrap":false}},"time":{"created":"2025-01-01T19:48:12.982Z","modified":"2025-09-09T13:18:50.353Z","0.0.1":"2025-01-01T19:48:13.331Z","0.1.0":"2025-01-02T07:32:39.200Z","0.1.1":"2025-01-02T17:41:46.192Z","0.1.2":"2025-09-09T13:18:50.137Z"},"bugs":{"url":"https://github.com/acalcutt/maplibre-contour-pmtiles/issues"},"author":{"name":"Michael Barry/Andrew Calcutt"},"license":"BSD-3-Clause","homepage":"https://github.com/acalcutt/maplibre-contour-pmtiles.git","repository":{"type":"git","url":"git+https://github.com/acalcutt/maplibre-contour-pmtiles.git"},"description":"Render contour lines from raster elevation tiles in maplibre-gl-js from pmtiles terrain sources","maintainers":[{"name":"acalcutt","email":"acalcutt@techidiots.net"}],"readme":"# maplibre-contour-pmtiles\r\n\r\nmaplibre-contour-pmtiles is a plugin to render contour lines in [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js) from `raster-dem` pmtiles sources. It was forked to support pmtiles with http support on the web and http and local supoort in node.js.\r\n\r\n![Topographic map of Mount Washington](demo.png)\r\n\r\n[Live example #1 (Just Terrain)](https://acalcutt.github.io/maplibre-contour-pmtiles/) | [Code](https://github.com/acalcutt/maplibre-contour-pmtiles/blob/pages/index.html)  \r\n[Live example #2 (w/ OpenMapTiles Style)](https://acalcutt.github.io/maplibre-contour-pmtiles/omt.html) | [Code](https://github.com/acalcutt/maplibre-contour-pmtiles/blob/pages/omt.html)  | [Style](https://acalcutt.github.io/maplibre-contour-pmtiles/styles/osm-bright-gl-style/style.json) \r\n\r\nTo use it, import the [@acalcutt/maplibre-contour-pmtiles](https://www.npmjs.com/package/@acalcutt/maplibre-contour-pmtiles) package with a script tag:\r\n\r\n```html\r\n<script src=\"https://unpkg.com/@acalcutt/maplibre-contour-pmtiles@latest/dist/maplibre-contour-pmtiles.min.js\"></script>\r\n```\r\n\r\nOr as an ES6 module: `npm add @acalcutt/maplibre-contour-pmtiles`\r\n\r\n```js\r\nimport mlcontour from \"@acalcutt/maplibre-contour-pmtiles\";\r\n```\r\n\r\nThen to use, first create a `DemSource` and register it with maplibre:\r\n\r\n```js\r\nvar demSource = new mlcontour.DemSource({\r\n  url: \"pmtiles://https://url/of/dem/source.pmtiles\",\r\n  encoding: \"mapbox\", // \"mapbox\" or \"terrarium\" default=\"terrarium\"\r\n  maxzoom: 12,\r\n  worker: true, // offload isoline computation to a web worker to reduce jank\r\n  cacheSize: 100, // number of most-recent tiles to cache\r\n  timeoutMs: 10_000, // timeout on fetch requests\r\n});\r\ndemSource.setupMaplibre(maplibregl);\r\n```\r\nWhen using scripts locally with node, url can also use the format\r\n```linux\r\n  url: \"pmtiles:///local/path/to/pmtiles/source.pmtiles\",\r\n```\r\n```windows\r\n  url: \"pmtiles://C://local//path//to//pmtiles//source.pmtiles\",\r\n```\r\n\r\nYou should also be able to use a regular non-pmtiles source with\r\n```js\r\n  url: \"https://url/of/dem/source/{z}/{x}/{y}.png\",\r\n```\r\n\r\nThen configure a new contour source and add it to your map:\r\n\r\n```js\r\nmap.addSource(\"contour-source\", {\r\n  type: \"vector\",\r\n  tiles: [\r\n    demSource.contourProtocolUrl({\r\n      // convert meters to feet, default=1 for meters\r\n      multiplier: 3.28084,\r\n      thresholds: {\r\n        // zoom: [minor, major]\r\n        11: [200, 1000],\r\n        12: [100, 500],\r\n        14: [50, 200],\r\n        15: [20, 100],\r\n      },\r\n      // optional, override vector tile parameters:\r\n      contourLayer: \"contours\",\r\n      elevationKey: \"ele\",\r\n      levelKey: \"level\",\r\n      extent: 4096,\r\n      buffer: 1,\r\n    }),\r\n  ],\r\n  maxzoom: 15,\r\n});\r\n```\r\n\r\nThen add contour line and label layers:\r\n\r\n```js\r\nmap.addLayer({\r\n  id: \"contour-lines\",\r\n  type: \"line\",\r\n  source: \"contour-source\",\r\n  \"source-layer\": \"contours\",\r\n  paint: {\r\n    \"line-color\": \"rgba(0,0,0, 50%)\",\r\n    // level = highest index in thresholds array the elevation is a multiple of\r\n    \"line-width\": [\"match\", [\"get\", \"level\"], 1, 1, 0.5],\r\n  },\r\n});\r\nmap.addLayer({\r\n  id: \"contour-labels\",\r\n  type: \"symbol\",\r\n  source: \"contour-source\",\r\n  \"source-layer\": \"contours\",\r\n  filter: [\">\", [\"get\", \"level\"], 0],\r\n  layout: {\r\n    \"symbol-placement\": \"line\",\r\n    \"text-size\": 10,\r\n    \"text-field\": [\"concat\", [\"number-format\", [\"get\", \"ele\"], {}], \"'\"],\r\n    \"text-font\": [\"Noto Sans Bold\"],\r\n  },\r\n  paint: {\r\n    \"text-halo-color\": \"white\",\r\n    \"text-halo-width\": 1,\r\n  },\r\n});\r\n```\r\n\r\nYou can also share the cached tiles with other maplibre sources that need elevation data:\r\n\r\n```js\r\nmap.addSource(\"dem\", {\r\n  type: \"raster-dem\",\r\n  encoding: \"terrarium\",\r\n  tiles: [demSource.sharedDemProtocolUrl],\r\n  maxzoom: 13,\r\n  tileSize: 256,\r\n});\r\n```\r\n\r\n# How it works\r\n\r\n<img src=\"architecture.png\" width=\"500\">\r\n\r\n[`DemSource.setupMaplibre`](./src/dem-source.ts) uses MapLibre's [`addProtocol`](https://maplibre.org/maplibre-gl-js-docs/api/properties/#addprotocol) utility to register a callback to provide vector tile for the contours source. Each time maplibre requests a vector tile:\r\n\r\n- [`DemManager`](./src/dem-manager.ts) fetches (and caches) the raster-dem image tile and its neighbors so that contours are continuous across tile boundaries.\r\n  - When `DemSource` is configured with `worker: true`, it uses [`RemoteDemManager`](./src/remote-dem-manager.ts) to spawn [`worker.ts`](./src/worker.ts) in a web worker. The web worker runs [`LocalDemManager`](./src/dem-manager.ts) locally and uses the [`Actor`](./src/actor.ts) utility to send cancelable requests and responses between the main and worker thread.\r\n- [`decode-image.ts`](./src/decode-image.ts) decodes the raster-dem image RGB values to meters above sea level for each pixel in the tile.\r\n- [`HeightTile`](./src/height-tile.ts) stitches those raw DEM tiles into a \"virtual tile\" that contains the border of neighboring tiles, aligns elevation measurements to the tile grid, and smooths the elevation measurements.\r\n- [`isoline.ts`](./src/isolines.ts) generates contour isolines from a `HeightTile` using a marching-squares implementation derived from [d3-contour](https://github.com/d3/d3-contour).\r\n- [`vtpbf.ts`](./src/vtpbf.ts) encodes the contour isolines as mapbox vector tile bytes.\r\n\r\nMapLibre sends that vector tile to its own worker, decodes it, and renders as if it had been generated by a server.\r\n\r\n# Why?\r\n\r\nThere are a lot of parameters you can tweak when generating contour lines from elevation data like units, thresholds, and smoothing parameters. Pre-generated contour vector tiles require 100+gb of storage for each variation you want to generate and host. Generating them on-the-fly in the browser gives infinite control over the variations you can use on a map from the same source of raw elevation data that maplibre uses to render hillshade.\r\n\r\n# License\r\n\r\nmaplibre-contour-pmtiles is licensed under the [BSD 3-Clause License](LICENSE). It includes code adapted from:\r\n\r\n- [d3-contour](https://github.com/d3/d3-contour) (ISC license)\r\n- [vt-pbf](https://github.com/mapbox/vt-pbf) (MIT license)\r\n- [PMTiles](https://github.com/protomaps/PMTiles) (BSD 3-Clause license)\r\n","readmeFilename":"README.md"}