@mapmap/maps 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -3
- package/dist/index.d.ts +935 -131
- package/dist/index.js +1353 -37
- package/dist/index.js.map +1 -1
- package/llms-sdk.txt +131 -0
- package/package.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logo.ts","../src/nav-design.ts","../src/style.ts","../src/map.ts","../src/coords.ts","../src/osrm.ts","../src/route.ts","../src/puck.ts","../src/places.ts","../src/camera.ts","../src/adr.ts","../src/guidance.ts"],"names":["lng","lat","maplibregl","DEFAULT_ZOOM","boundsOf"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The MapMap logo control: a small wordmark on the map, the same\n * convention as Google Maps' and Mapbox's marks. On by default in\n * {@link MapMapMap}; positionable, and removable with `logo: false`\n * (attribution itself is separate and never removable).\n *\n * The mark is an inline SVG (no network fetch, works offline and under\n * strict CSPs): the MapMap brand lockup — the three-colour route mark\n * plus the lowercase wordmark. Height stays at 20px so existing layouts\n * hold.\n */\n\n/** Corner positions accepted by the logo control. */\nexport type LogoPosition = \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n\n/** Options for {@link LogoControl}. */\nexport interface LogoOptions {\n /** Corner to render in. Default `bottom-right`, above the attribution. */\n position?: LogoPosition;\n /** Link target when clicked. Default the MapMap site. */\n href?: string;\n}\n\n/**\n * The inline wordmark (height 20px): the outline-light lockup — the\n * line-art route mark plus the dark wordmark — over a white halo stroke\n * so it stays legible on any base map.\n */\nexport const LOGO_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"84\" height=\"20\" viewBox=\"0 0 156 37\" fill=\"none\" role=\"img\" aria-label=\"MapMap\">' +\n '<g stroke=\"#ffffff\" stroke-linejoin=\"round\" stroke-linecap=\"round\">' +\n '<path d=\"M146.965 19.2363C146.965 17.5281 146.64 16.2469 145.989 15.3927C145.358 14.5386 144.464 14.1115 143.304 14.1115C142.227 14.1115 141.352 14.5589 140.681 15.4537C140.03 16.3282 139.705 17.5382 139.705 19.0838V19.3889C139.705 20.9751 140.03 22.2055 140.681 23.08C141.352 23.9341 142.227 24.3612 143.304 24.3612C144.382 24.3612 145.257 23.924 145.928 23.0495C146.619 22.1547 146.965 20.8836 146.965 19.2363ZM150.778 19.2363C150.778 21.8598 150.188 23.8934 149.009 25.3373C147.85 26.7609 146.324 27.4727 144.433 27.4727C142.481 27.4727 140.925 26.7304 139.766 25.2458H139.705V33.8787H135.739V11.305H139.461L139.522 13.5319H139.583C140.803 11.844 142.42 11 144.433 11C146.406 11 147.951 11.7016 149.07 13.1048C150.209 14.5081 150.778 16.5519 150.778 19.2363Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M126.399 11C128.819 11 130.558 11.4779 131.615 12.4337C132.673 13.3692 133.202 14.8945 133.202 17.0095V22.8969C133.202 24.3409 133.354 25.7644 133.659 27.1676H129.907C129.785 26.4965 129.694 25.7136 129.633 24.8188H129.572C129.002 25.6526 128.229 26.3033 127.253 26.7711C126.297 27.2388 125.25 27.4727 124.111 27.4727C122.627 27.4727 121.437 27.066 120.542 26.2525C119.668 25.4187 119.23 24.2697 119.23 22.8054C119.23 21.0361 119.973 19.6227 121.457 18.5652C122.962 17.4874 125.118 16.9485 127.924 16.9485H129.236V16.857C129.236 15.7791 129.023 15.0267 128.596 14.5996C128.168 14.1725 127.406 13.959 126.308 13.959C124.315 13.959 122.433 14.4166 120.664 15.3317L120.085 12.3727C122.017 11.4576 124.121 11 126.399 11ZM122.952 22.5004C122.952 23.1512 123.145 23.6596 123.532 24.0256C123.918 24.3917 124.447 24.5747 125.118 24.5747C126.277 24.5747 127.253 24.1985 128.046 23.446C128.84 22.6936 129.236 21.7479 129.236 20.6091V19.5719H127.924C126.318 19.5719 125.087 19.8464 124.233 20.3955C123.379 20.9243 122.952 21.6259 122.952 22.5004Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M96.1152 11.305H99.7758L99.8673 13.4404H99.9284C101.108 11.8135 102.46 11 103.986 11C104.982 11 105.806 11.2034 106.456 11.6101C107.107 12.0168 107.666 12.6778 108.134 13.5929H108.195C109.517 11.8643 111.073 11 112.862 11C114.571 11 115.811 11.4779 116.584 12.4337C117.377 13.3692 117.774 14.9555 117.774 17.1925V27.1676H113.93V18.1077C113.93 16.5214 113.757 15.4537 113.412 14.9046C113.086 14.3555 112.496 14.081 111.642 14.081C110.91 14.081 110.27 14.4674 109.72 15.2402C109.171 16.013 108.897 16.9688 108.897 18.1077V27.1676H105.053V18.1077C105.053 16.5214 104.88 15.4537 104.535 14.9046C104.209 14.3555 103.619 14.081 102.765 14.081C102.033 14.081 101.393 14.4674 100.844 15.2402C100.294 16.013 100.02 16.9688 100.02 18.1077V27.1676H96.1152V11.305Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M90.8503 19.2363C90.8503 17.5281 90.525 16.2469 89.8742 15.3927C89.2438 14.5386 88.3489 14.1115 87.1898 14.1115C86.1119 14.1115 85.2374 14.5589 84.5663 15.4537C83.9155 16.3282 83.5902 17.5382 83.5902 19.0838V19.3889C83.5902 20.9751 83.9155 22.2055 84.5663 23.08C85.2374 23.9341 86.1119 24.3612 87.1898 24.3612C88.2676 24.3612 89.1421 23.924 89.8132 23.0495C90.5046 22.1547 90.8503 20.8836 90.8503 19.2363ZM94.6635 19.2363C94.6635 21.8598 94.0737 23.8934 92.8942 25.3373C91.735 26.7609 90.2097 27.4727 88.3184 27.4727C86.3661 27.4727 84.8104 26.7304 83.6512 25.2458H83.5902V33.8787H79.6245V11.305H83.3461L83.4071 13.5319H83.4681C84.6883 11.844 86.3051 11 88.3184 11C90.2911 11 91.8367 11.7016 92.9552 13.1048C94.094 14.5081 94.6635 16.5519 94.6635 19.2363Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M70.2844 11C72.7045 11 74.4432 11.4779 75.5008 12.4337C76.5583 13.3692 77.087 14.8945 77.087 17.0095V22.8969C77.087 24.3409 77.2395 25.7644 77.5446 27.1676H73.7925C73.6705 26.4965 73.5789 25.7136 73.5179 24.8188H73.4569C72.8875 25.6526 72.1147 26.3033 71.1385 26.7711C70.1827 27.2388 69.1354 27.4727 67.9965 27.4727C66.5119 27.4727 65.3223 27.066 64.4274 26.2525C63.553 25.4187 63.1157 24.2697 63.1157 22.8054C63.1157 21.0361 63.858 19.6227 65.3426 18.5652C66.8475 17.4874 69.0032 16.9485 71.8096 16.9485H73.1214V16.857C73.1214 15.7791 72.9078 15.0267 72.4808 14.5996C72.0537 14.1725 71.2911 13.959 70.1929 13.959C68.1999 13.959 66.3187 14.4166 64.5495 15.3317L63.9699 12.3727C65.9018 11.4576 68.0067 11 70.2844 11ZM66.8373 22.5004C66.8373 23.1512 67.0305 23.6596 67.4169 24.0256C67.8033 24.3917 68.3321 24.5747 69.0032 24.5747C70.1624 24.5747 71.1385 24.1985 71.9317 23.446C72.7248 22.6936 73.1214 21.7479 73.1214 20.6091V19.5719H71.8096C70.203 19.5719 68.9727 19.8464 68.1185 20.3955C67.2644 20.9243 66.8373 21.6259 66.8373 22.5004Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M40 11.3049H43.6606L43.7521 13.4403H43.8131C44.9927 11.8133 46.345 10.9999 47.8703 10.9999C48.8668 10.9999 49.6904 11.2032 50.3412 11.61C50.992 12.0167 51.5512 12.6777 52.019 13.5928H52.08C53.4019 11.8642 54.9576 10.9999 56.7472 10.9999C58.4555 10.9999 59.6961 11.4778 60.4689 12.4336C61.262 13.3691 61.6586 14.9554 61.6586 17.1924V27.1675H57.8149V18.1075C57.8149 16.5213 57.6421 15.4536 57.2963 14.9045C56.9709 14.3554 56.3812 14.0809 55.527 14.0809C54.7949 14.0809 54.1543 14.4673 53.6052 15.2401C53.0561 16.0129 52.7816 16.9687 52.7816 18.1075V27.1675H48.938V18.1075C48.938 16.5213 48.7651 15.4536 48.4194 14.9045C48.094 14.3554 47.5042 14.0809 46.6501 14.0809C45.918 14.0809 45.2774 14.4673 44.7283 15.2401C44.1792 16.0129 43.9046 16.9687 43.9046 18.1075V27.1675H40V11.3049Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke-width=\"4.96\"/>' +\n '<path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke-width=\"4.96\"/>' +\n '<path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke-width=\"4.96\"/>' +\n '</g>' +\n '<path d=\"M146.965 19.2363C146.965 17.5281 146.64 16.2469 145.989 15.3927C145.358 14.5386 144.464 14.1115 143.304 14.1115C142.227 14.1115 141.352 14.5589 140.681 15.4537C140.03 16.3282 139.705 17.5382 139.705 19.0838V19.3889C139.705 20.9751 140.03 22.2055 140.681 23.08C141.352 23.9341 142.227 24.3612 143.304 24.3612C144.382 24.3612 145.257 23.924 145.928 23.0495C146.619 22.1547 146.965 20.8836 146.965 19.2363ZM150.778 19.2363C150.778 21.8598 150.188 23.8934 149.009 25.3373C147.85 26.7609 146.324 27.4727 144.433 27.4727C142.481 27.4727 140.925 26.7304 139.766 25.2458H139.705V33.8787H135.739V11.305H139.461L139.522 13.5319H139.583C140.803 11.844 142.42 11 144.433 11C146.406 11 147.951 11.7016 149.07 13.1048C150.209 14.5081 150.778 16.5519 150.778 19.2363Z\" fill=\"#26282A\"/>' +\n '<path d=\"M126.399 11C128.819 11 130.558 11.4779 131.615 12.4337C132.673 13.3692 133.202 14.8945 133.202 17.0095V22.8969C133.202 24.3409 133.354 25.7644 133.659 27.1676H129.907C129.785 26.4965 129.694 25.7136 129.633 24.8188H129.572C129.002 25.6526 128.229 26.3033 127.253 26.7711C126.297 27.2388 125.25 27.4727 124.111 27.4727C122.627 27.4727 121.437 27.066 120.542 26.2525C119.668 25.4187 119.23 24.2697 119.23 22.8054C119.23 21.0361 119.973 19.6227 121.457 18.5652C122.962 17.4874 125.118 16.9485 127.924 16.9485H129.236V16.857C129.236 15.7791 129.023 15.0267 128.596 14.5996C128.168 14.1725 127.406 13.959 126.308 13.959C124.315 13.959 122.433 14.4166 120.664 15.3317L120.085 12.3727C122.017 11.4576 124.121 11 126.399 11ZM122.952 22.5004C122.952 23.1512 123.145 23.6596 123.532 24.0256C123.918 24.3917 124.447 24.5747 125.118 24.5747C126.277 24.5747 127.253 24.1985 128.046 23.446C128.84 22.6936 129.236 21.7479 129.236 20.6091V19.5719H127.924C126.318 19.5719 125.087 19.8464 124.233 20.3955C123.379 20.9243 122.952 21.6259 122.952 22.5004Z\" fill=\"#26282A\"/>' +\n '<path d=\"M96.1152 11.305H99.7758L99.8673 13.4404H99.9284C101.108 11.8135 102.46 11 103.986 11C104.982 11 105.806 11.2034 106.456 11.6101C107.107 12.0168 107.666 12.6778 108.134 13.5929H108.195C109.517 11.8643 111.073 11 112.862 11C114.571 11 115.811 11.4779 116.584 12.4337C117.377 13.3692 117.774 14.9555 117.774 17.1925V27.1676H113.93V18.1077C113.93 16.5214 113.757 15.4537 113.412 14.9046C113.086 14.3555 112.496 14.081 111.642 14.081C110.91 14.081 110.27 14.4674 109.72 15.2402C109.171 16.013 108.897 16.9688 108.897 18.1077V27.1676H105.053V18.1077C105.053 16.5214 104.88 15.4537 104.535 14.9046C104.209 14.3555 103.619 14.081 102.765 14.081C102.033 14.081 101.393 14.4674 100.844 15.2402C100.294 16.013 100.02 16.9688 100.02 18.1077V27.1676H96.1152V11.305Z\" fill=\"#26282A\"/>' +\n '<path d=\"M90.8503 19.2363C90.8503 17.5281 90.525 16.2469 89.8742 15.3927C89.2438 14.5386 88.3489 14.1115 87.1898 14.1115C86.1119 14.1115 85.2374 14.5589 84.5663 15.4537C83.9155 16.3282 83.5902 17.5382 83.5902 19.0838V19.3889C83.5902 20.9751 83.9155 22.2055 84.5663 23.08C85.2374 23.9341 86.1119 24.3612 87.1898 24.3612C88.2676 24.3612 89.1421 23.924 89.8132 23.0495C90.5046 22.1547 90.8503 20.8836 90.8503 19.2363ZM94.6635 19.2363C94.6635 21.8598 94.0737 23.8934 92.8942 25.3373C91.735 26.7609 90.2097 27.4727 88.3184 27.4727C86.3661 27.4727 84.8104 26.7304 83.6512 25.2458H83.5902V33.8787H79.6245V11.305H83.3461L83.4071 13.5319H83.4681C84.6883 11.844 86.3051 11 88.3184 11C90.2911 11 91.8367 11.7016 92.9552 13.1048C94.094 14.5081 94.6635 16.5519 94.6635 19.2363Z\" fill=\"#26282A\"/>' +\n '<path d=\"M70.2844 11C72.7045 11 74.4432 11.4779 75.5008 12.4337C76.5583 13.3692 77.087 14.8945 77.087 17.0095V22.8969C77.087 24.3409 77.2395 25.7644 77.5446 27.1676H73.7925C73.6705 26.4965 73.5789 25.7136 73.5179 24.8188H73.4569C72.8875 25.6526 72.1147 26.3033 71.1385 26.7711C70.1827 27.2388 69.1354 27.4727 67.9965 27.4727C66.5119 27.4727 65.3223 27.066 64.4274 26.2525C63.553 25.4187 63.1157 24.2697 63.1157 22.8054C63.1157 21.0361 63.858 19.6227 65.3426 18.5652C66.8475 17.4874 69.0032 16.9485 71.8096 16.9485H73.1214V16.857C73.1214 15.7791 72.9078 15.0267 72.4808 14.5996C72.0537 14.1725 71.2911 13.959 70.1929 13.959C68.1999 13.959 66.3187 14.4166 64.5495 15.3317L63.9699 12.3727C65.9018 11.4576 68.0067 11 70.2844 11ZM66.8373 22.5004C66.8373 23.1512 67.0305 23.6596 67.4169 24.0256C67.8033 24.3917 68.3321 24.5747 69.0032 24.5747C70.1624 24.5747 71.1385 24.1985 71.9317 23.446C72.7248 22.6936 73.1214 21.7479 73.1214 20.6091V19.5719H71.8096C70.203 19.5719 68.9727 19.8464 68.1185 20.3955C67.2644 20.9243 66.8373 21.6259 66.8373 22.5004Z\" fill=\"#26282A\"/>' +\n '<path d=\"M40 11.3049H43.6606L43.7521 13.4403H43.8131C44.9927 11.8133 46.345 10.9999 47.8703 10.9999C48.8668 10.9999 49.6904 11.2032 50.3412 11.61C50.992 12.0167 51.5512 12.6777 52.019 13.5928H52.08C53.4019 11.8642 54.9576 10.9999 56.7472 10.9999C58.4555 10.9999 59.6961 11.4778 60.4689 12.4336C61.262 13.3691 61.6586 14.9554 61.6586 17.1924V27.1675H57.8149V18.1075C57.8149 16.5213 57.6421 15.4536 57.2963 14.9045C56.9709 14.3554 56.3812 14.0809 55.527 14.0809C54.7949 14.0809 54.1543 14.4673 53.6052 15.2401C53.0561 16.0129 52.7816 16.9687 52.7816 18.1075V27.1675H48.938V18.1075C48.938 16.5213 48.7651 15.4536 48.4194 14.9045C48.094 14.3554 47.5042 14.0809 46.6501 14.0809C45.918 14.0809 45.2774 14.4673 44.7283 15.2401C44.1792 16.0129 43.9046 16.9687 43.9046 18.1075V27.1675H40V11.3049Z\" fill=\"#26282A\"/>' +\n '<path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '<path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '<path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '</svg>';\n\nconst DEFAULT_HREF = \"https://mapmap.ai\";\n\n/**\n * A MapLibre `IControl` rendering the MapMap wordmark. Typed structurally\n * (`onAdd`/`onRemove`) so it needs no maplibre-gl import and works with\n * any instance the host app bundles.\n */\nexport class LogoControl {\n private container: HTMLElement | undefined;\n private readonly href: string;\n\n constructor(options: LogoOptions = {}) {\n this.href = options.href ?? DEFAULT_HREF;\n }\n\n onAdd(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"LogoControl requires a DOM environment\");\n const link = doc.createElement(\"a\");\n link.className = \"maplibregl-ctrl mapmap-logo\";\n link.href = this.href;\n link.target = \"_blank\";\n link.rel = \"noopener\";\n link.setAttribute(\"aria-label\", \"MapMap\");\n link.style.cssText =\n \"display:block;line-height:0;margin:0 8px 4px 8px;opacity:0.9;pointer-events:auto\";\n // LOGO_SVG is a compile-time constant, parsed rather than assigned to\n // innerHTML so no HTML-injection surface exists even if it changes.\n const svg = new DOMParser().parseFromString(LOGO_SVG, \"image/svg+xml\").documentElement;\n link.appendChild(doc.importNode(svg, true));\n this.container = link;\n return link;\n }\n\n onRemove(): void {\n this.container?.remove();\n this.container = undefined;\n }\n}\n","/**\n * Studio navigation-design block (`extra.nav`) - types, defaults and parser.\n *\n * MapMap Studio's Navigation panel designs the turn-by-turn look - route\n * line, current-position puck and banner instruction - and stores the result\n * as a small design-token block under `extra.nav` in the theme JSON it\n * downloads/copies. This module reads that block so the same theme file\n * styles real navigation UI: `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` all accept a design from it.\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-nav.ts` (the Studio\n * reference parser) - identical interfaces, defaults, clamps and URL rules.\n * Keep the two in sync so a theme previews in Studio exactly as the SDK\n * renders it. Not imported from the website because the packages do not\n * depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. That includes hosted publishing: the canonical\n * `sn_style` crate stores `extra` verbatim (bounded at 256 KB serialised)\n * and the gateway serves it back from `GET /styles/{id}/theme`, so a design\n * survives Studio's publish flow too. Read it from a theme file you pass to\n * `createMap` / `buildStyle`, or fetch it from a hosted style with\n * {@link navDesignFromThemeUrl} — a compiled style URL alone never carries\n * it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** Route-line tokens (defaults match {@link RouteLayer}'s built-in look). */\nexport interface NavRouteDesign {\n /** Line colour. Default is MapMap signal blue (`SIGNAL_BLUE`). */\n color: string;\n /** Line width in px at mid zoom. */\n width: number;\n /** Line opacity, 0-1. */\n opacity: number;\n /** Casing (outline) colour drawn under the line. */\n casingColor: string;\n}\n\n/** Current-position puck tokens. */\nexport interface NavPuckDesign {\n /** Puck fill colour. */\n color: string;\n /** Puck diameter in px. */\n size: number;\n /** Whether the heading arrow is drawn on the puck. */\n headingArrow: boolean;\n /**\n * Optional custom puck image (`https:` or `data:` URI, PNG/SVG). When set\n * it replaces the built-in dot + arrow; `size` still scales it. Optional\n * since v1 - themes saved without it load unchanged.\n */\n imageUrl?: string;\n}\n\n/** Banner-instruction tokens (defaults match {@link GuidanceBanner}). */\nexport interface NavBannerDesign {\n /** Banner background colour. */\n background: string;\n /** Banner text (and arrow) colour. */\n textColor: string;\n /** Primary text size in px. */\n fontSize: number;\n /** Whether the lane diagram row is shown when lanes are present. */\n showLanes: boolean;\n /** Inner padding in px, 6-24. Optional since v1; default 10. */\n padding?: number;\n /** Corner radius in px, 0-24. Optional since v1; default 10. */\n cornerRadius?: number;\n /** Maximum banner width in px, 200-520. Optional since v1; default 340. */\n maxWidth?: number;\n /**\n * Banner height in px, 40-120. Optional since v1; unset means auto -\n * the banner takes its natural content height (old themes keep theirs).\n */\n height?: number;\n}\n\n/**\n * Drive-camera tokens: how the chase cam frames a turn-by-turn drive.\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and the SDK keeps its built-in framing. Every field is itself\n * optional (absent = the documented default). `NavigationCamera` reads\n * `pitch`/`zoom` as its option defaults; `speedMps` drives Studio's demo\n * drive (and any route simulator) - a camera following real GPS fixes\n * ignores it.\n */\nexport interface NavCameraDesign {\n /** Chase-cam tilt in degrees, 0-85. Default 60. */\n pitch?: number;\n /** Chase-cam zoom, 14-20. Default 17.5. */\n zoom?: number;\n /** Drive speed in metres per second, 2-40. Default 12 (~43 km/h). */\n speedMps?: number;\n}\n\n/**\n * Defaults for the optional `camera` block. LOCKSTEP: mirrors\n * `NAV_CAMERA_DEFAULTS` in `website/lib/studio-nav.ts`.\n */\nexport const NAV_CAMERA_DEFAULTS = {\n pitch: 60,\n zoom: 17.5,\n speedMps: 12,\n} as const;\n\n/** The `extra.nav` block: navigation design tokens for the SDKs. */\nexport interface NavDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n route: NavRouteDesign;\n puck: NavPuckDesign;\n banner: NavBannerDesign;\n /**\n * Optional since v1: drive-camera framing (pitch/zoom) and speed. Absent\n * means \"SDK built-ins\" - the block stays `version: 1` either way.\n */\n camera?: NavCameraDesign;\n}\n\n/**\n * Defaults mirror what the SDK draws today with no design: `RouteLayer`'s\n * signal-blue line over a dark casing, and `GuidanceBanner`'s dark pill.\n */\nexport function defaultNavDesign(): NavDesign {\n return {\n version: 1,\n route: { color: \"#3a86ff\", width: 4.5, opacity: 1, casingColor: \"#1f438a\" },\n puck: { color: \"#1f6fff\", size: 14, headingArrow: true },\n banner: {\n background: \"#101418\",\n textColor: \"#ffffff\",\n fontSize: 16,\n showLanes: true,\n padding: 10,\n cornerRadius: 10,\n maxWidth: 340,\n },\n };\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction str(v: unknown, fallback: string): string {\n return typeof v === \"string\" && v.trim() !== \"\" ? v : fallback;\n}\n\nfunction num(v: unknown, fallback: number, min: number, max: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : fallback;\n}\n\n/** Optional clamped number: absent/malformed stays `undefined` (= auto). */\nfunction optNum(v: unknown, min: number, max: number): number | undefined {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : undefined;\n}\n\nfunction bool(v: unknown, fallback: boolean): boolean {\n return typeof v === \"boolean\" ? v : fallback;\n}\n\n/**\n * Optional puck-image URL: only `https:` or `data:` URIs are accepted;\n * anything else (including absence) yields `undefined` - the built-in puck.\n */\nfunction puckImageUrl(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return /^(https:|data:)/i.test(t) ? t : undefined;\n}\n\n/**\n * Lenient parse of an `extra.nav` value: unknown or malformed fields fall\n * back to the defaults, so an imported theme never fails on its nav block.\n * LOCKSTEP: identical semantics to `parseNavDesign` in\n * `website/lib/studio-nav.ts` (same clamps, same fallbacks).\n */\nexport function parseNavDesign(value: unknown): NavDesign {\n const d = defaultNavDesign();\n if (!isRecord(value)) return d;\n const route = isRecord(value.route) ? value.route : {};\n const puck = isRecord(value.puck) ? value.puck : {};\n const banner = isRecord(value.banner) ? value.banner : {};\n return {\n version: 1,\n route: {\n color: str(route.color, d.route.color),\n width: num(route.width, d.route.width, 0.5, 20),\n opacity: num(route.opacity, d.route.opacity, 0, 1),\n casingColor: str(route.casingColor, d.route.casingColor),\n },\n puck: {\n color: str(puck.color, d.puck.color),\n size: num(puck.size, d.puck.size, 6, 40),\n headingArrow: bool(puck.headingArrow, d.puck.headingArrow),\n imageUrl: puckImageUrl(puck.imageUrl),\n },\n banner: {\n background: str(banner.background, d.banner.background),\n textColor: str(banner.textColor, d.banner.textColor),\n fontSize: num(banner.fontSize, d.banner.fontSize, 10, 32),\n showLanes: bool(banner.showLanes, d.banner.showLanes),\n padding: num(banner.padding, d.banner.padding ?? 10, 6, 24),\n cornerRadius: num(banner.cornerRadius, d.banner.cornerRadius ?? 10, 0, 24),\n maxWidth: num(banner.maxWidth, d.banner.maxWidth ?? 340, 200, 520),\n height: optNum(banner.height, 40, 120),\n },\n // Camera is optional since v1: absent (or malformed) stays undefined so\n // old themes round-trip byte-identical; a present block clamps per\n // field, each absent field meaning \"use the default\".\n ...(isRecord(value.camera)\n ? {\n camera: {\n pitch: optNum(value.camera.pitch, 0, 85),\n zoom: optNum(value.camera.zoom, 14, 20),\n speedMps: optNum(value.camera.speedMps, 2, 40),\n },\n }\n : {}),\n };\n}\n\n/**\n * Reads and parses the `extra.nav` block from a Studio theme document.\n * Returns `undefined` when the theme carries no nav block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults.\n */\nexport function navDesignFromTheme(theme: Theme | undefined | null): NavDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"nav\" in extra)) {\n return undefined;\n }\n return parseNavDesign((extra as { nav?: unknown }).nav);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.nav` block.\n *\n * Point it at the gateway's theme endpoint - the design a Studio publish\n * stores alongside the compiled style:\n *\n * ```ts\n * const design = await navDesignFromThemeUrl(\n * \"https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme\",\n * );\n * ```\n *\n * The endpoint is public (no API key) and never cached, so this always\n * reflects the latest published version. Returns `undefined` when the\n * theme carries no nav block (same contract as {@link navDesignFromTheme});\n * throws on network failure, a non-2xx response or a non-JSON body.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n * Defaults to the global `fetch`.\n */\nexport async function navDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<NavDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return navDesignFromTheme(theme);\n}\n","/**\n * MapMap style assembly - pure, browser-free port of the `sn-style` crate.\n *\n * This module mirrors `crates/sn-style` (theme.rs + compile.rs), the\n * canonical MapMap Studio theme engine, so client-side and build-side\n * styles compile identically. A {@link Theme} is a small, agent-friendly\n * JSON document (named palette slots + per-layer overrides) that\n * {@link buildStyle} turns into a full MapLibre style-spec v8 style over\n * the MapMap territory tiles (OpenMapTiles schema, as emitted by\n * `sn-factory`'s Planetiler stage and served as PMTiles).\n *\n * The `pmtiles://` URL prefix is resolved by the pmtiles protocol handler\n * that {@link registerPmtilesProtocol} installs on the MapLibre instance.\n *\n * Attribution: \"© OpenStreetMap contributors\" (ODbL) and \"© OpenMapTiles\"\n * (CC-BY 4.0 schema) are legally required and stamped on every compiled\n * style's tile source. There is no theme field that can remove them.\n */\nimport type { StyleSpecification } from \"maplibre-gl\";\n\n/** A loose JSON object - skeleton layers are assembled as plain JSON. */\ntype JsonObject = Record<string, unknown>;\n\n/** Which built-in palette a theme starts from. */\nexport type MapMapTheme = \"light\" | \"dark\";\n\n/** The OSM attribution string. Legally required (ODbL) - never removed. */\nexport const OSM_ATTRIBUTION = \"© OpenStreetMap contributors\";\n\n/** The OpenMapTiles schema attribution (CC-BY 4.0). */\nexport const OPENMAPTILES_ATTRIBUTION = \"© OpenMapTiles\";\n\n/**\n * Combined attribution stamped on every compiled style's tile source.\n * Legally required (ODbL + CC-BY) - enforced, not themable: no theme\n * field can remove it.\n */\nexport const FULL_ATTRIBUTION = \"© OpenStreetMap contributors © OpenMapTiles\";\n\n/** Default glyph endpoint (PBF fontstacks), mirroring `sn_style::DEFAULT_GLYPHS_URL`. */\nexport const DEFAULT_GLYPHS_URL = \"https://fonts.mapmap.ai/{fontstack}/{range}.pbf\";\n\n/** A sensible default territory tiles URL (overridable per map). */\nexport const DEFAULT_TERRITORY_TILES_URL =\n \"pmtiles://https://tiles.mapmap.ai/territories/planet.pmtiles\";\n\n/**\n * Every source-layer the Planetiler (OpenMapTiles-schema) tiles emit.\n * The style skeleton covers all of them; extra layers referencing anything\n * else are rejected. Mirrors `sn_style::SOURCE_LAYERS`.\n */\nexport const SOURCE_LAYERS: readonly string[] = [\n \"aerodrome_label\",\n \"aeroway\",\n \"boundary\",\n \"building\",\n \"housenumber\",\n \"landcover\",\n \"landuse\",\n \"mountain_peak\",\n \"park\",\n \"place\",\n \"poi\",\n \"transportation\",\n \"transportation_name\",\n \"water\",\n \"water_name\",\n \"waterway\",\n];\n\n/**\n * The named palette slots as `[slot, lightDefault, darkDefault]`, mirroring\n * `sn_style::palette_slots()`. Order is stable and documentation-worthy: it\n * is the order a Studio UI should present them in.\n */\nexport const PALETTE_SLOTS: readonly (readonly [string, string, string])[] = [\n [\"background\", \"#f4f2ee\", \"#12161c\"],\n [\"water\", \"#a8c8e8\", \"#1b2c40\"],\n [\"waterway\", \"#a8c8e8\", \"#1b2c40\"],\n [\"landcover\", \"#e3e8dd\", \"#182029\"],\n [\"landuse\", \"#ece8e1\", \"#171e26\"],\n [\"park\", \"#cfe4c8\", \"#1a2a1f\"],\n [\"building\", \"#e2ddd4\", \"#20272f\"],\n [\"aeroway\", \"#dcd9d2\", \"#232b34\"],\n [\"road\", \"#ffffff\", \"#2b333d\"],\n [\"roadMajor\", \"#f6d9a0\", \"#4a5461\"],\n [\"path\", \"#d9d4ca\", \"#2a323c\"],\n [\"rail\", \"#d0cbc2\", \"#262e37\"],\n [\"boundary\", \"#b9a6c9\", \"#4a3d57\"],\n [\"boundaryMinor\", \"#c9bcd6\", \"#3a3247\"],\n [\"textPrimary\", \"#3a3a3a\", \"#d6dbe1\"],\n [\"textSecondary\", \"#6b6b6b\", \"#9aa3ad\"],\n [\"textHalo\", \"#ffffff\", \"#12161c\"],\n];\n\n/**\n * Per-layer override: merged onto the skeleton layer with the same id.\n * Mirrors `sn_style::LayerOverride`.\n */\nexport interface LayerOverride {\n /** Hide the layer entirely (`layout.visibility = \"none\"`). */\n visible?: boolean;\n /** Paint properties merged over the skeleton's (per-key, override wins). */\n paint?: Record<string, unknown>;\n /** Layout properties merged over the skeleton's. */\n layout?: Record<string, unknown>;\n /** Replace the skeleton's filter (per-attribute styling hook). */\n filter?: unknown;\n minzoom?: number;\n maxzoom?: number;\n}\n\n/**\n * A MapMap Studio theme: the unit users and agents edit, store and publish.\n * Mirrors `sn_style::Theme` (all fields carry serde defaults, so everything\n * is optional here).\n */\nexport interface Theme {\n /** Human-readable theme name, e.g. `\"midnight-fleet\"`. */\n name?: string;\n /** Built-in palette to start from. Defaults to `\"light\"`. */\n base?: MapMapTheme;\n /** Palette overrides by slot name (see {@link PALETTE_SLOTS}). */\n palette?: Record<string, string>;\n /** Per-layer overrides by skeleton layer id. */\n layers?: Record<string, LayerOverride>;\n /**\n * Render buildings as 3D extrusions. Adds a `building-3d` fill-extrusion\n * layer (zoom 15+) driven by the tiles' `render_height` /\n * `render_min_height` attributes, and caps the flat `building` footprint\n * layer at that zoom so the two hand off cleanly (the extrusion rises\n * from flat as you zoom in). Web-safe; native navigation SDKs should\n * leave this off by default until MapLibre Native's fill-extrusion\n * memory use at street zooms is fixed (maplibre-native#4107). Mirrors\n * `Theme::buildings_3d`.\n */\n buildings_3d?: boolean;\n /**\n * Label fonts. Every fontstack must exist on the glyph server; until that\n * ships (P2), leave this at its default (`\"Noto Sans Regular\"`).\n */\n fonts?: { regular?: string };\n /** Override the glyph endpoint (defaults to {@link DEFAULT_GLYPHS_URL}). */\n glyphs?: string;\n /** Optional sprite URL (icons/shields - P2, no default sprite exists). */\n sprite?: string;\n /**\n * Extra fully-formed MapLibre layers appended above the skeleton (below\n * labels). Each must reference the `territory` source and a known\n * source-layer.\n */\n extra_layers?: JsonObject[];\n /**\n * Non-style extras carried by the THEME DOCUMENT, not the compiled\n * style. Studio stores its navigation design block here (`extra.nav`;\n * see `nav-design.ts`). {@link buildStyle} ignores it entirely - the\n * compiled `style.json` is byte-identical with or without it. Mirrors\n * `Theme::extra` in the canonical Rust crate: the hosted styles API\n * stores the block verbatim (bounded at 256 KB serialised) and serves it\n * back from `GET /styles/{id}/theme`, so a Studio design survives\n * publishing - consume it via `createMap` with a theme document or\n * `navDesignFromThemeUrl` with the hosted theme URL.\n */\n extra?: { nav?: unknown };\n}\n\nexport interface BuildStyleOptions {\n /**\n * Theme to build: a built-in name (`\"light\"` / `\"dark\"`) or a full\n * {@link Theme} document. Defaults to `\"light\"`.\n */\n theme?: MapMapTheme | Theme;\n /**\n * PMTiles URL for the territory tiles. Accepts either a `pmtiles://…` URL\n * or a plain `https://…` URL (the `pmtiles://` prefix is added for you).\n */\n territoryTilesUrl?: string;\n}\n\n/** Ensure a tiles URL carries the `pmtiles://` protocol prefix. */\nexport function toPmtilesUrl(url: string): string {\n return url.startsWith(\"pmtiles://\") ? url : `pmtiles://${url}`;\n}\n\n/**\n * Cheap CSS colour check: hex forms and the functional notations MapLibre\n * accepts. Deliberately permissive on the inside of `rgb()`/`hsl()`.\n * Mirrors `sn_style::theme::is_css_colour`.\n */\nfunction isCssColour(value: string): boolean {\n const v = value.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n return (\n [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex)\n );\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (v.startsWith(prefix) && v.endsWith(\")\")) return true;\n }\n return false;\n}\n\n/**\n * Resolve the effective palette for a theme: base defaults + overrides.\n * Fails on unknown slots or unparseable colours (agent self-correction).\n * Mirrors `sn_style::theme::resolve_palette`.\n */\nfunction resolvePalette(theme: Theme): Record<string, string> {\n const base = theme.base ?? \"light\";\n const palette: Record<string, string> = {};\n // Membership is checked against the slot list, not with `in` (which would\n // accept Object.prototype keys like \"toString\" that the Rust compiler\n // rejects as UnknownPaletteSlot).\n const knownSlots = new Set(PALETTE_SLOTS.map(([slot]) => slot));\n for (const [slot, light, dark] of PALETTE_SLOTS) {\n palette[slot] = base === \"dark\" ? dark : light;\n }\n for (const [slot, value] of Object.entries(theme.palette ?? {})) {\n if (!knownSlots.has(slot)) {\n const accepted = PALETTE_SLOTS.map(([s]) => s).join(\", \");\n throw new Error(\n `unknown palette slot ${JSON.stringify(slot)}; accepted slots: ${accepted}`,\n );\n }\n if (!isCssColour(value)) {\n throw new Error(\n `palette slot ${JSON.stringify(slot)} has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n palette[slot] = value;\n }\n return palette;\n}\n\n/** Skeleton fill layer, mirroring `compile.rs`'s `fill()` helper. */\nfunction fill(\n id: string,\n sourceLayer: string,\n colour: string,\n opacity: number,\n minzoom?: number,\n): JsonObject {\n const layer: JsonObject = {\n id,\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n paint: { \"fill-color\": colour, \"fill-opacity\": opacity },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Skeleton symbol layer, mirroring `compile.rs`'s `symbol()` helper. */\nfunction symbol(\n id: string,\n sourceLayer: string,\n textField: unknown,\n font: readonly string[],\n textSize: unknown,\n colour: string,\n halo: string,\n minzoom?: number,\n extraLayout?: JsonObject,\n): JsonObject {\n const layout: JsonObject = {\n \"text-field\": textField,\n \"text-font\": font,\n \"text-size\": textSize,\n ...extraLayout,\n };\n const layer: JsonObject = {\n id,\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n layout,\n paint: {\n \"text-color\": colour,\n \"text-halo-color\": halo,\n \"text-halo-width\": 1.2,\n },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Apply a per-layer override, mirroring `compile.rs`'s `apply_override`. */\nfunction applyOverride(layer: JsonObject, layerOverride: LayerOverride): void {\n if (layerOverride.paint) mergeObject(layer, \"paint\", layerOverride.paint);\n if (layerOverride.layout) mergeObject(layer, \"layout\", layerOverride.layout);\n if (layerOverride.filter !== undefined) layer[\"filter\"] = layerOverride.filter;\n if (layerOverride.minzoom !== undefined) layer[\"minzoom\"] = layerOverride.minzoom;\n if (layerOverride.maxzoom !== undefined) layer[\"maxzoom\"] = layerOverride.maxzoom;\n if (layerOverride.visible === false) {\n const layout = (layer[\"layout\"] ??= {}) as JsonObject;\n layout[\"visibility\"] = \"none\";\n }\n}\n\nfunction mergeObject(\n layer: JsonObject,\n key: \"paint\" | \"layout\",\n overrides: Record<string, unknown>,\n): void {\n const target = (layer[key] ??= {}) as JsonObject;\n for (const [k, v] of Object.entries(overrides)) target[k] = v;\n}\n\n/** Validate one extra layer, mirroring `compile.rs`'s `validate_extra_layer`. */\nfunction validateExtraLayer(index: number, layer: unknown): JsonObject {\n const invalid = (reason: string): Error =>\n new Error(`extra layer ${index} is invalid: ${reason}`);\n if (typeof layer !== \"object\" || layer === null || Array.isArray(layer)) {\n throw invalid(\"must be an object\");\n }\n const obj = layer as JsonObject;\n const id = obj[\"id\"];\n if (typeof id !== \"string\") throw invalid('must have a string \"id\"');\n if (id.length === 0) throw invalid('\"id\" must be non-empty');\n if (obj[\"type\"] !== \"background\") {\n if (obj[\"source\"] !== \"territory\") {\n throw invalid('\"source\" must be \"territory\"');\n }\n const sourceLayer = obj[\"source-layer\"];\n if (typeof sourceLayer !== \"string\") {\n throw invalid('must have a string \"source-layer\"');\n }\n if (!SOURCE_LAYERS.includes(sourceLayer)) {\n throw invalid(\n `unknown source-layer ${JSON.stringify(sourceLayer)}; accepted: ` +\n SOURCE_LAYERS.join(\", \"),\n );\n }\n }\n return obj;\n}\n\n/**\n * Assemble a full MapLibre style for the MapMap tiles - a faithful port of\n * `sn_style::compile`, so a {@link Theme} compiles to the same style here\n * as it does in `sn-factory`/`sn-gateway`. Pure: returns a plain object,\n * touches no browser APIs, and is safe to snapshot in tests.\n *\n * Throws an `Error` with an agent-readable message (offending key + the\n * accepted values) on unknown palette slots, invalid colours, unknown layer\n * ids and invalid extra layers, mirroring `sn_style::StyleError`.\n */\n/**\n * The accepted top-level {@link Theme} keys (mirrors serde\n * `deny_unknown_fields`). `extra` is the one deliberate divergence from the\n * Rust crate: it carries Studio's nav design block in the theme FILE and is\n * ignored by compilation (the gateway still rejects it on `/styles`, which\n * is why Studio strips it on publish).\n */\nconst THEME_KEYS: readonly string[] = [\n \"name\",\n \"base\",\n \"palette\",\n \"layers\",\n \"fonts\",\n \"glyphs\",\n \"sprite\",\n \"extra_layers\",\n \"extra\",\n \"buildings_3d\",\n];\n\n/**\n * Zoom at which 3D building extrusions start (and the flat footprint layer\n * stops) when a theme sets `buildings_3d`. Mirrors\n * `compile.rs::BUILDINGS_3D_MINZOOM`. Exported for\n * `MapMapMap.setBuildings3d`, which performs the same handoff at runtime.\n */\nexport const BUILDINGS_3D_MINZOOM = 15;\n\n/**\n * The `building-3d` fill-extrusion layer a theme with `buildings_3d` gets:\n * heights from the tiles' `render_height`/`render_min_height` (5 m coalesce\n * fallback for tiles missing them), rising from flat over half a zoom so\n * the handoff from the footprint layer is seamless. Mirrors the layer\n * `compile.rs` emits, byte for byte. Shared by {@link buildStyle} and\n * `MapMapMap.setBuildings3d` so the two can never drift.\n */\nexport function buildings3dLayer(colour: unknown): JsonObject {\n return {\n id: \"building-3d\",\n type: \"fill-extrusion\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"fill-extrusion-color\": colour,\n \"fill-extrusion-height\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_height\"], 5],\n ],\n \"fill-extrusion-base\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_min_height\"], 0],\n ],\n \"fill-extrusion-opacity\": 0.85,\n \"fill-extrusion-vertical-gradient\": true,\n },\n };\n}\n\nexport function buildStyle(options: BuildStyleOptions = {}): StyleSpecification {\n const input = options.theme ?? \"light\";\n if (typeof input === \"object\") {\n // Mirror the Rust Theme's serde deny_unknown_fields: a typo'd key\n // (e.g. \"extraLayers\", \"pallete\") must fail loudly here too, not\n // silently render the default style.\n for (const key of Object.keys(input)) {\n if (!THEME_KEYS.includes(key)) {\n throw new Error(\n `unknown theme field ${JSON.stringify(key)}; accepted fields: ` +\n THEME_KEYS.join(\", \"),\n );\n }\n }\n }\n const theme: Theme =\n typeof input === \"string\" ? { name: input, base: input } : input;\n const palette = resolvePalette(theme);\n const p = (slot: string): string => palette[slot] as string;\n const font = [theme.fonts?.regular ?? \"Noto Sans Regular\"] as const;\n const nameField = [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n const tilesUrl = toPmtilesUrl(\n options.territoryTilesUrl ?? DEFAULT_TERRITORY_TILES_URL,\n );\n\n // The skeleton: every OpenMapTiles source-layer styled, palette-driven.\n // Order is paint order (first = bottom). Mirrors compile.rs exactly.\n const layers: JsonObject[] = [\n {\n id: \"background\",\n type: \"background\",\n paint: { \"background-color\": p(\"background\") },\n },\n fill(\"landcover\", \"landcover\", p(\"landcover\"), 0.6),\n fill(\"landuse\", \"landuse\", p(\"landuse\"), 0.45),\n fill(\"park\", \"park\", p(\"park\"), 0.7),\n fill(\"water\", \"water\", p(\"water\"), 1.0),\n {\n id: \"waterway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"waterway\",\n paint: {\n \"line-color\": p(\"waterway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 3],\n },\n },\n {\n id: \"aeroway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"aeroway\",\n minzoom: 10,\n filter: [\"in\", \"class\", \"runway\", \"taxiway\"],\n paint: {\n \"line-color\": p(\"aeroway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 10, 1, 16, 6],\n },\n },\n fill(\"building\", \"building\", p(\"building\"), 0.9, 13),\n {\n id: \"rail\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 8,\n filter: [\"in\", \"class\", \"rail\", \"transit\"],\n paint: {\n \"line-color\": p(\"rail\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.4, 16, 2],\n },\n },\n {\n id: \"road-path\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"in\", \"class\", \"path\", \"track\", \"pedestrian\"],\n paint: {\n \"line-color\": p(\"path\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 13, 0.5, 16, 2],\n \"line-dasharray\": [2, 1],\n },\n },\n {\n id: \"road-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n paint: {\n \"line-color\": p(\"road\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 4],\n },\n },\n {\n id: \"road-major\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n paint: {\n \"line-color\": p(\"roadMajor\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 6, 1, 16, 8],\n },\n },\n {\n id: \"boundary-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n minzoom: 6,\n filter: [\"all\", [\">=\", \"admin_level\", 3], [\"<=\", \"admin_level\", 8]],\n paint: {\n \"line-color\": p(\"boundaryMinor\"),\n \"line-width\": 0.6,\n \"line-dasharray\": [2, 2],\n },\n },\n {\n id: \"boundary\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n filter: [\"<=\", \"admin_level\", 2],\n paint: {\n \"line-color\": p(\"boundary\"),\n \"line-width\": 1,\n \"line-dasharray\": [3, 2],\n },\n },\n ];\n\n // 3D buildings: a fill-extrusion layer above the road network (2D layers\n // drawn after an extrusion paint over its pitched volumes, so it must\n // come last in the base map), below extras and labels. The flat\n // footprint layer is capped at the extrusion minzoom. Mirrors compile.rs.\n if (theme.buildings_3d) {\n const flat = layers.find((l) => l[\"id\"] === \"building\") as JsonObject;\n flat[\"maxzoom\"] = BUILDINGS_3D_MINZOOM;\n layers.push(buildings3dLayer(p(\"building\")));\n }\n\n // User/agent-supplied extra layers sit above the base map, below labels.\n (theme.extra_layers ?? []).forEach((extra, index) => {\n layers.push(structuredClone(validateExtraLayer(index, extra)));\n });\n\n layers.push(\n symbol(\n \"housenumber\",\n \"housenumber\",\n [\"get\", \"housenumber\"],\n font,\n 10,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 17,\n ),\n symbol(\n \"road-labels\",\n \"transportation_name\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 12,\n { \"symbol-placement\": \"line\" },\n ),\n symbol(\n \"water-name\",\n \"water_name\",\n nameField,\n font,\n 12,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"poi-labels\",\n \"poi\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 14,\n { \"text-anchor\": \"top\" },\n ),\n symbol(\n \"mountain-peak-labels\",\n \"mountain_peak\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"aerodrome-labels\",\n \"aerodrome_label\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 10,\n ),\n symbol(\n \"place-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 4, 11, 12, 16],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n ),\n );\n\n // Reject duplicate layer ids (e.g. an extra layer reusing a skeleton id),\n // mirroring `validate_style` in sn-style's validate.rs — the Rust compiler\n // rejects these and MapLibre would error at style load.\n const seenIds = new Set<string>();\n for (const layer of layers) {\n const layerId = layer[\"id\"] as string;\n if (seenIds.has(layerId)) {\n throw new Error(`duplicate layer id ${JSON.stringify(layerId)}`);\n }\n seenIds.add(layerId);\n }\n\n // Apply per-layer overrides.\n const accepted = layers.map((l) => l[\"id\"] as string).join(\", \");\n for (const [id, layerOverride] of Object.entries(theme.layers ?? {})) {\n const layer = layers.find((l) => l[\"id\"] === id);\n if (!layer) {\n throw new Error(\n `unknown layer id ${JSON.stringify(id)}; accepted ids: ${accepted}`,\n );\n }\n applyOverride(layer, layerOverride);\n }\n\n const style: JsonObject = {\n version: 8,\n name: theme.name ? `MapMap ${theme.name}` : \"MapMap\",\n glyphs: theme.glyphs ?? DEFAULT_GLYPHS_URL,\n sources: {\n territory: {\n type: \"vector\",\n url: tilesUrl,\n // Legally required (ODbL + CC-BY) - enforced, not themable. There\n // is no theme field that can remove it.\n attribution: FULL_ATTRIBUTION,\n },\n },\n layers,\n };\n if (theme.sprite !== undefined) style[\"sprite\"] = theme.sprite;\n\n // The object above is structurally a MapLibre style; the cast avoids\n // hand-satisfying every discriminated-union member of StyleSpecification.\n return style as unknown as StyleSpecification;\n}\n","/**\n * MapMapMap - the branded MapLibre GL map.\n *\n * A thin wrapper over `maplibregl.Map`. MapLibre does all the rendering; this\n * class only wires in the MapMap default style, registers the pmtiles\n * protocol, and keeps the gateway `apiKey`/`baseUrl` handy so routing and ADR\n * helpers can reuse them.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n LayerSpecification,\n Map as MlMap,\n MapOptions,\n StyleSpecification,\n} from \"maplibre-gl\";\nimport { Protocol } from \"pmtiles\";\nimport { LogoControl, type LogoOptions } from \"./logo.js\";\nimport { navDesignFromTheme, type NavDesign } from \"./nav-design.js\";\nimport {\n BUILDINGS_3D_MINZOOM,\n buildStyle,\n buildings3dLayer,\n type MapMapTheme,\n type Theme,\n} from \"./style.js\";\n\n// Tracked per maplibre-gl module instance, not with a single flag: bundlers\n// can duplicate maplibre-gl, and each copy needs its own registration.\nconst pmtilesRegistered = new WeakSet<object>();\n\n/**\n * Register the `pmtiles://` protocol on a MapLibre instance. Idempotent per\n * maplibre-gl instance, and safe to call before constructing any map.\n * Exposed for apps that build their own `maplibregl.Map` (possibly from\n * their own bundled maplibre-gl copy) but still want to read MapMap PMTiles.\n */\nexport function registerPmtilesProtocol(gl: typeof maplibregl = maplibregl): void {\n if (pmtilesRegistered.has(gl)) return;\n const protocol = new Protocol();\n gl.addProtocol(\"pmtiles\", protocol.tile);\n pmtilesRegistered.add(gl);\n}\n\nexport interface MapMapOptions {\n /**\n * The MapMap wordmark on the map (like the Google Maps / Mapbox marks).\n * Default on at bottom-right, above the attribution; `false` removes\n * it, or pass `{ position, href }` to customise.\n */\n logo?: boolean | LogoOptions;\n /** The container element or its id. */\n container: string | HTMLElement;\n /** Gateway API key (`snk_…`), used by routing and ADR helpers. */\n apiKey?: string;\n /** Gateway base URL for routing/ADR. Defaults to `https://api.mapmap.ai`. */\n baseUrl?: string;\n /**\n * Style to load. A theme name (`\"light\"` / `\"dark\"`), a MapMap Studio\n * `Theme` document, a full MapLibre `StyleSpecification`, or a style URL.\n * Defaults to `\"light\"`.\n */\n style?: MapMapTheme | Theme | StyleSpecification | string;\n /** Override the territory PMTiles URL used by the default styles. */\n territoryTilesUrl?: string;\n /** Initial centre as `[lng, lat]`. Defaults to the UK. */\n center?: [number, number];\n /** Initial zoom. Defaults to `5`. */\n zoom?: number;\n /**\n * Extra MapLibre `MapOptions` merged last (escape hatch for hash, bearing,\n * maxBounds, etc.). `container` and `style` here are ignored.\n */\n mapOptions?: Partial<Omit<MapOptions, \"container\" | \"style\">>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.mapmap.ai\";\nconst DEFAULT_CENTER: [number, number] = [-1.5, 52.6];\nconst DEFAULT_ZOOM = 5;\n\n/** The MapMap map: a branded, tiles-and-routing-ready MapLibre map. */\nexport class MapMapMap {\n /** The underlying MapLibre map. Use it for any native MapLibre call. */\n readonly map: MlMap;\n /** Gateway API key, if provided. */\n readonly apiKey: string | undefined;\n /** Gateway base URL (no trailing slash). */\n readonly baseUrl: string;\n /**\n * The Studio navigation design (`extra.nav`) parsed from the theme passed\n * as `style`, when it carried one. `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` pick this up as their default look; `undefined` means\n * the theme had no nav block (or `style` was not a theme document).\n */\n readonly navDesign: NavDesign | undefined;\n\n constructor(options: MapMapOptions) {\n registerPmtilesProtocol();\n\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.navDesign = navDesignFromTheme(themeOf(options.style));\n\n const style = resolveStyle(options.style, options.territoryTilesUrl);\n\n this.map = new maplibregl.Map({\n container: options.container,\n style,\n center: options.center ?? DEFAULT_CENTER,\n zoom: options.zoom ?? DEFAULT_ZOOM,\n attributionControl: { compact: false },\n ...options.mapOptions,\n });\n\n // The MapMap mark, Google/Mapbox-style. Default on (bottom-right,\n // above the attribution); `logo: false` removes it, `logo: {...}`\n // repositions it. Attribution is separate and never removable.\n if (options.logo !== false) {\n const logoOptions = options.logo === true ? {} : (options.logo ?? {});\n this.map.addControl(\n new LogoControl(logoOptions),\n logoOptions.position ?? \"bottom-right\",\n );\n }\n }\n\n /**\n * Toggle 3D building extrusions at runtime — the live equivalent of\n * compiling the style with `buildings_3d: true` (see `Theme`): adds or\n * removes the `building-3d` fill-extrusion layer and hands the flat\n * `building` footprint layer off at zoom 15. The extrusion takes its\n * colour from the current `building` fill, so it follows the theme.\n * Idempotent; safe to call before the style has loaded (it applies on\n * load). Requires the MapMap skeleton's `building` layer — on a custom\n * style without one this throws rather than guessing.\n *\n * Mobile note: leave 3D off in native navigation views for now\n * (maplibre-native#4107 — fill-extrusion memory at street zooms).\n */\n setBuildings3d(enabled: boolean): void {\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.setBuildings3d(enabled));\n return;\n }\n if (enabled === (this.map.getLayer(\"building-3d\") !== undefined)) return;\n const building = this.map.getLayer(\"building\");\n if (!building) {\n throw new Error(\n 'setBuildings3d needs the MapMap skeleton \"building\" layer; ' +\n \"the current style does not have one\",\n );\n }\n const minzoom = building.minzoom ?? 13;\n if (enabled) {\n const colour =\n this.map.getPaintProperty(\"building\", \"fill-color\") ?? \"#e2ddd4\";\n this.map.addLayer(\n buildings3dLayer(colour) as unknown as LayerSpecification,\n buildings3dBeforeId(this.map),\n );\n this.map.setLayerZoomRange(\"building\", minzoom, BUILDINGS_3D_MINZOOM);\n } else {\n this.map.removeLayer(\"building-3d\");\n // 24 is the style-spec default maxzoom, i.e. \"uncapped\".\n this.map.setLayerZoomRange(\"building\", minzoom, 24);\n }\n }\n\n /** Resolves once the style and first tiles are loaded. */\n whenReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.map.loaded()) {\n resolve();\n return;\n }\n this.map.once(\"load\", () => resolve());\n });\n }\n\n /** Remove the map and release its WebGL context. */\n destroy(): void {\n this.map.remove();\n }\n}\n\n/** Functional alias for {@link MapMapMap}, mirroring the Mapbox `new Map` feel. */\nexport function createMap(options: MapMapOptions): MapMapMap {\n return new MapMapMap(options);\n}\n\n/**\n * Where the runtime `building-3d` layer goes: the same place the compiler\n * puts it — directly above the base map (after `boundary`), below extras\n * and labels. On a custom style without the skeleton's `boundary` layer,\n * fall back to just below the first symbol layer; `undefined` (append on\n * top) only if there are no symbol layers either.\n */\nfunction buildings3dBeforeId(map: MlMap): string | undefined {\n const layers = map.getStyle().layers ?? [];\n const boundary = layers.findIndex((l) => l.id === \"boundary\");\n if (boundary >= 0) return layers[boundary + 1]?.id;\n return layers.find((l) => l.type === \"symbol\")?.id;\n}\n\n/**\n * The MapMap Studio Theme document behind a `style` option, if that is what\n * it is. An object without a `version` field is a Theme; a full MapLibre\n * StyleSpecification always carries `version: 8`.\n */\nfunction themeOf(style: MapMapOptions[\"style\"]): Theme | undefined {\n if (typeof style === \"object\" && style !== null && !(\"version\" in style)) {\n return style as Theme;\n }\n return undefined;\n}\n\nfunction resolveStyle(\n style: MapMapOptions[\"style\"],\n territoryTilesUrl: string | undefined,\n): StyleSpecification | string {\n if (style === undefined || style === \"light\" || style === \"dark\") {\n return buildStyle({\n theme: style ?? \"light\",\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n const theme = themeOf(style);\n if (theme) {\n return buildStyle({\n theme,\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n return style as StyleSpecification | string;\n}\n","/**\n * Coordinate helpers - pure, browser-free logic.\n *\n * The gateway speaks the OSRM HTTP API: coordinates are `lon,lat` pairs\n * separated by `;`. MapLibre and GeoJSON use `[lng, lat]` order, so the one\n * job here is to normalise the three accepted input shapes into that wire\n * format without ever swapping the axes by accident.\n */\nimport type { LngLatLike } from \"./types.js\";\n\n/** Normalise any accepted shape to a `[lng, lat]` tuple. */\nexport function toLngLat(point: LngLatLike): [number, number] {\n if (Array.isArray(point)) {\n const [lng, lat] = point;\n assertFinite(lng, lat);\n return [lng, lat];\n }\n const lng = \"lng\" in point ? point.lng : point.lon;\n const lat = point.lat;\n assertFinite(lng, lat);\n return [lng, lat];\n}\n\n/** Format one point as an OSRM `lon,lat` coordinate. */\nexport function formatCoord(point: LngLatLike): string {\n const [lng, lat] = toLngLat(point);\n return `${lng},${lat}`;\n}\n\n/**\n * Format an ordered list of points as an OSRM coordinate path\n * (`lon,lat;lon,lat;…`). At least two points are required, matching the\n * gateway, which rejects single-coordinate requests.\n */\nexport function formatCoords(points: LngLatLike[]): string {\n if (points.length < 2) {\n throw new Error(\"at least two coordinates are required for a route\");\n }\n return points.map(formatCoord).join(\";\");\n}\n\nfunction assertFinite(lng: number, lat: number): void {\n if (!Number.isFinite(lng) || !Number.isFinite(lat)) {\n throw new Error(`invalid coordinate: lng=${lng}, lat=${lat}`);\n }\n if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {\n throw new Error(\n `coordinate out of range: lng=${lng} (±180), lat=${lat} (±90) - check lng/lat order`,\n );\n }\n}\n","/**\n * OSRM request assembly and response parsing - pure, browser-free logic.\n *\n * The MapMap gateway exposes `GET /route/v1/{profile}/{coordinates}` speaking\n * the OSRM HTTP API v1, with truck vendor extensions (`height`, `width`,\n * `length`, `weight`, `hazmat`, `tunnel_code`). We always request\n * `geometries=geojson` so the route line arrives as a GeoJSON LineString we\n * can hand straight to a MapLibre source.\n */\nimport { formatCoords } from \"./coords.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteGeometry,\n RouteProfile,\n TruckParams,\n} from \"./types.js\";\n\n/** Guidance-related query options. */\nexport interface GuidanceQuery {\n voice?: boolean;\n banner?: boolean;\n language?: string;\n}\n\n/** Build the OSRM query string (without the leading `?`) for a request. */\nexport function buildRouteQuery(truck?: TruckParams, guidance?: GuidanceQuery): string {\n const params = new URLSearchParams({\n geometries: \"geojson\",\n overview: \"full\",\n steps: \"true\",\n });\n if (guidance?.voice) params.set(\"voice_instructions\", \"true\");\n if (guidance?.banner) params.set(\"banner_instructions\", \"true\");\n if (guidance?.language) params.set(\"language\", guidance.language);\n if (truck) {\n if (truck.heightM != null) params.set(\"height\", String(truck.heightM));\n if (truck.widthM != null) params.set(\"width\", String(truck.widthM));\n if (truck.lengthM != null) params.set(\"length\", String(truck.lengthM));\n if (truck.weightT != null) params.set(\"weight\", String(truck.weightT));\n if (truck.hazmat != null) params.set(\"hazmat\", String(truck.hazmat));\n // URLSearchParams encodes the slash in codes like \"B/D\" for us.\n if (truck.tunnelCode != null) params.set(\"tunnel_code\", truck.tunnelCode);\n }\n return params.toString();\n}\n\n/**\n * Build the full OSRM route URL. `baseUrl` is the gateway origin (trailing\n * slashes are trimmed); `points` is the ordered coordinate path.\n */\nexport function buildRouteUrl(\n baseUrl: string,\n profile: RouteProfile,\n points: LngLatLike[],\n truck?: TruckParams,\n guidance?: GuidanceQuery,\n): string {\n const origin = baseUrl.replace(/\\/+$/, \"\");\n const coords = formatCoords(points);\n const query = buildRouteQuery(truck, guidance);\n return `${origin}/route/v1/${encodeURIComponent(profile)}/${coords}?${query}`;\n}\n\n/**\n * Parse an OSRM route response into a {@link ParsedRoute}. Throws with the\n * OSRM `code`/`message` when the response is not `Ok` or carries no route.\n */\nexport function parseOsrmRoute(body: unknown): ParsedRoute {\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"OSRM response was not an object\");\n }\n const obj = body as Record<string, unknown>;\n const code = obj[\"code\"];\n if (code !== \"Ok\") {\n const message = typeof obj[\"message\"] === \"string\" ? obj[\"message\"] : \"\";\n throw new Error(\n `OSRM routing failed: ${String(code)}${message ? ` - ${message}` : \"\"}`,\n );\n }\n\n const routes = obj[\"routes\"];\n if (!Array.isArray(routes) || routes.length === 0) {\n throw new Error(\"OSRM response contained no routes\");\n }\n const route = routes[0] as Record<string, unknown>;\n\n const geometry = parseGeometry(route[\"geometry\"]);\n const distanceM = numberOr(route[\"distance\"], 0);\n const durationS = numberOr(route[\"duration\"], 0);\n\n return { distanceM, durationS, geometry, raw: route };\n}\n\nfunction parseGeometry(geometry: unknown): RouteGeometry {\n if (\n typeof geometry !== \"object\" ||\n geometry === null ||\n (geometry as { type?: unknown }).type !== \"LineString\"\n ) {\n throw new Error(\n \"route geometry was not GeoJSON - request geometries=geojson\",\n );\n }\n const coordinates = (geometry as { coordinates?: unknown }).coordinates;\n if (!Array.isArray(coordinates)) {\n throw new Error(\"route geometry had no coordinates\");\n }\n const positions: [number, number][] = coordinates.map((pos, i) => {\n if (\n !Array.isArray(pos) ||\n typeof pos[0] !== \"number\" ||\n typeof pos[1] !== \"number\"\n ) {\n throw new Error(`route geometry position ${i} is not [lng, lat]`);\n }\n return [pos[0], pos[1]];\n });\n return { type: \"LineString\", coordinates: positions };\n}\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n","/**\n * RouteLayer - fetch an OSRM route from the MapMap gateway and draw it.\n *\n * The route request/parse logic lives in the pure `osrm` module; this class\n * owns the network call and the MapLibre source/layers (a signal-blue line\n * with a darker casing, matching the brand).\n */\nimport type {\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n} from \"maplibre-gl\";\nimport { buildRouteUrl, parseOsrmRoute } from \"./osrm.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteOptions,\n} from \"./types.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { NavRouteDesign } from \"./nav-design.js\";\n\n/** MapMap brand signal blue (see website `--signal`). */\nexport const SIGNAL_BLUE = \"#3a86ff\";\nconst CASING_COLOR = \"#1f438a\";\n\nexport interface RouteLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-route\"`. */\n id?: string;\n /**\n * Studio route design (`extra.nav` `route` block). Defaults to the map's\n * `navDesign.route` when given a `MapMapMap` whose theme carried one;\n * without a design the layer keeps its built-in signal-blue look.\n */\n design?: NavRouteDesign;\n}\n\n/** Draws MapMap routes on a MapLibre map. */\nexport class RouteLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly casingLayerId: string;\n private readonly lineLayerId: string;\n private readonly design: NavRouteDesign | undefined;\n private lastRoute: ParsedRoute | undefined;\n\n constructor(map: MapMapMap | MlMap, options: RouteLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n this.design = options.design ?? map.navDesign?.route;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\"RouteLayer needs a baseUrl when given a raw MapLibre map\");\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.design = options.design;\n }\n const id = options.id ?? \"mapmap-route\";\n this.sourceId = `${id}-src`;\n this.casingLayerId = `${id}-casing`;\n this.lineLayerId = `${id}-line`;\n // MapLibre wipes runtime sources/layers on every setStyle (e.g. a\n // light/dark theme swap), so re-install the route after each style\n // load — the same pattern the playground uses. This also completes a\n // draw() that arrived before the initial style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastRoute) this.install(this.lastRoute);\n };\n\n /**\n * Route from `from` to `to` (with optional intermediate `via` points passed\n * through `options` is not supported here - pass a coordinate list to\n * {@link routePath} for that), draw the line, and return the parsed route.\n */\n async route(\n from: LngLatLike,\n to: LngLatLike,\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n return this.routePath([from, to], options);\n }\n\n /** Route through an ordered list of coordinates and draw the result. */\n async routePath(\n points: LngLatLike[],\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n const url = buildRouteUrl(\n this.baseUrl,\n options.profile ?? \"driving\",\n points,\n options.truck,\n { voice: options.voice, banner: options.banner, language: options.language },\n );\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(url, { headers });\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const obj =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n // Only OSRM-shaped error bodies (with a \"code\") belong to the routing\n // engine; anything else (e.g. the gateway's RFC 9457 problem+json for\n // 401/429) is reported with its status and title/detail instead of\n // being misattributed as an OSRM failure.\n if (typeof obj?.[\"code\"] !== \"string\") {\n const context = [obj?.[\"title\"], obj?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `route request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n }\n const parsed = parseOsrmRoute(body);\n this.draw(parsed);\n return parsed;\n }\n\n /** The most recently drawn route, if any. */\n get current(): ParsedRoute | undefined {\n return this.lastRoute;\n }\n\n /**\n * Draw (or update) a parsed route's line on the map. Safe to call before\n * the style has loaded: the route is stored and installed on the next\n * `style.load` instead of throwing MapLibre's \"Style is not done loading\".\n */\n draw(route: ParsedRoute): void {\n this.lastRoute = route;\n if (!this.map.isStyleLoaded()) return; // installed by handleStyleLoad\n this.install(route);\n }\n\n /** Add-or-update the source and layers for a route on the current style. */\n private install(route: ParsedRoute): void {\n const data = {\n type: \"Feature\" as const,\n properties: {},\n geometry: route.geometry,\n };\n\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, { type: \"geojson\", data });\n }\n\n if (this.map.getLayer(this.casingLayerId) && this.map.getLayer(this.lineLayerId)) {\n return;\n }\n\n // With a Studio design the paints follow the Studio preview exactly\n // (constant width, casing = width + 4, shared opacity — see\n // syncNavOverlay in the Studio client); without one they keep the\n // built-in zoom-interpolated signal-blue look, unchanged.\n const casing: LineLayerSpecification = {\n id: this.casingLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.casingColor,\n \"line-width\": this.design.width + 4,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": CASING_COLOR,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 6, 16, 12],\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.color,\n \"line-width\": this.design.width,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": SIGNAL_BLUE,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 3, 16, 8],\n },\n };\n\n if (!this.map.getLayer(this.casingLayerId)) this.map.addLayer(casing);\n if (!this.map.getLayer(this.lineLayerId)) this.map.addLayer(line);\n }\n\n /** Remove the route's layers and source from the map. */\n clear(): void {\n for (const layerId of [this.lineLayerId, this.casingLayerId]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastRoute = undefined;\n }\n\n /**\n * Remove the route and detach the layer's `style.load` listener. Call\n * when disposing of the layer (the map itself is left untouched).\n */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * PositionPuck - the current-position marker, styled by a Studio design.\n *\n * A MapLibre `Marker`-based puck: a coloured dot with an optional heading\n * arrow, or a custom image (`https:`/`data:` URI, data payloads capped at\n * 64 KB - the same cap Studio enforces on upload) that replaces both and\n * falls back to the built-in dot if it fails to load. The marker survives\n * `setStyle` on its own (markers are DOM overlays, not style layers), so\n * no `style.load` re-install is needed.\n *\n * LOCKSTEP: the element structure and styling mirror `createPuckElement` /\n * `stylePuckElement` in the Studio client\n * (`website/app/studio/StudioClient.tsx`), so a theme's puck renders here\n * exactly as Studio previews it.\n *\n * Like `MapMapMap` (see map.ts), this module imports the SDK's bundled\n * maplibre-gl for the `Marker` constructor - a purely structural typing\n * (the `LogoControl` pattern) is not possible because a Marker must be\n * constructed, not just duck-typed.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type { Map as MlMap, Marker } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { defaultNavDesign, type NavPuckDesign } from \"./nav-design.js\";\n\n/** Maximum accepted `data:` puck-image payload (matches Studio's upload cap). */\nexport const MAX_PUCK_IMAGE_BYTES = 64 * 1024;\n\n/**\n * Approximate decoded byte size of a `data:` URI payload (base64 payloads\n * decode to 3/4 of their character count; other payloads are counted as-is,\n * an upper bound for percent-encoded text).\n */\nfunction dataUriBytes(uri: string): number {\n const comma = uri.indexOf(\",\");\n const payload = comma === -1 ? \"\" : uri.slice(comma + 1);\n const meta = comma === -1 ? uri : uri.slice(0, comma);\n return /;base64$/i.test(meta) || /;base64;/i.test(meta)\n ? Math.floor((payload.length * 3) / 4)\n : payload.length;\n}\n\n/** The design's image URL, or `undefined` when unusable (built-in puck). */\nfunction effectiveImageUrl(design: NavPuckDesign): string | undefined {\n const url = design.imageUrl?.trim();\n if (!url) return undefined;\n if (/^data:/i.test(url) && dataUriBytes(url) > MAX_PUCK_IMAGE_BYTES) {\n return undefined;\n }\n return url;\n}\n\n/** A current-position puck marker for MapMap maps. */\nexport class PositionPuck {\n /** The puck's root DOM element (the Marker element). */\n readonly element: HTMLElement;\n private readonly map: MlMap;\n private readonly marker: Marker;\n private readonly design: NavPuckDesign;\n private added = false;\n\n /**\n * Creates the puck (not yet on the map - it appears on the first\n * {@link setLocation}). The design defaults to the map's\n * `navDesign.puck` when given a `MapMapMap` whose theme carried an\n * `extra.nav` block, then to the built-in blue puck.\n */\n constructor(map: MapMapMap | MlMap, design?: NavPuckDesign) {\n this.map = map instanceof MapMapMap ? map.map : map;\n this.design =\n design ??\n (map instanceof MapMapMap ? map.navDesign?.puck : undefined) ??\n defaultNavDesign().puck;\n this.element = createPuckElement();\n stylePuckElement(this.element, this.design);\n // Map-aligned rotation/pitch: the puck lies flat on the map and its\n // heading rotates with the camera bearing, as in the Studio preview.\n this.marker = new maplibregl.Marker({\n element: this.element,\n rotationAlignment: \"map\",\n pitchAlignment: \"map\",\n });\n }\n\n /**\n * Moves the puck (adding it to the map on the first call). `headingDeg`\n * rotates the whole element - arrow or custom image - clockwise from\n * north; omit it to keep the previous heading.\n */\n setLocation(location: { lat: number; lon: number }, headingDeg?: number): void {\n this.marker.setLngLat([location.lon, location.lat]);\n if (headingDeg !== undefined) this.marker.setRotation(headingDeg);\n if (!this.added) {\n this.marker.addTo(this.map);\n this.added = true;\n }\n }\n\n /** Removes the puck from the map. `setLocation` re-adds it. */\n remove(): void {\n this.marker.remove();\n this.added = false;\n }\n}\n\n/**\n * The puck element: a dot plus an optional heading-arrow triangle, and a\n * (hidden by default) custom-image slot that replaces both when the design\n * carries an `imageUrl`. LOCKSTEP with Studio's `createPuckElement`.\n */\nfunction createPuckElement(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"PositionPuck requires a DOM environment\");\n const el = doc.createElement(\"div\");\n el.className = \"mapmap-puck\";\n el.style.position = \"relative\";\n const arrow = doc.createElement(\"div\");\n arrow.dataset[\"part\"] = \"arrow\";\n const dot = doc.createElement(\"div\");\n dot.dataset[\"part\"] = \"dot\";\n const img = doc.createElement(\"img\");\n img.dataset[\"part\"] = \"image\";\n img.alt = \"\";\n img.draggable = false;\n img.style.display = \"none\";\n el.append(arrow, dot, img);\n return el;\n}\n\n/**\n * Applies a puck design to the element. LOCKSTEP with Studio's\n * `stylePuckElement`: same sizes, colours, shadows and image fallback (a\n * URL that fails to load is remembered on the element and the built-in\n * puck shows instead).\n */\nfunction stylePuckElement(el: HTMLElement, puck: NavPuckDesign): void {\n const dot = el.querySelector<HTMLElement>(\"[data-part='dot']\");\n const arrow = el.querySelector<HTMLElement>(\"[data-part='arrow']\");\n const img = el.querySelector<HTMLImageElement>(\"[data-part='image']\");\n if (!dot || !arrow || !img) return;\n const s = puck.size;\n el.style.width = `${s}px`;\n el.style.height = `${s}px`;\n const url = effectiveImageUrl(puck) ?? \"\";\n if (url !== \"\" && el.dataset[\"imageFailed\"] !== url) {\n if (img.getAttribute(\"src\") !== url) {\n img.onerror = () => {\n el.dataset[\"imageFailed\"] = url;\n img.removeAttribute(\"src\");\n stylePuckElement(el, puck);\n };\n img.src = url;\n }\n img.style.cssText =\n `display:block;position:absolute;inset:0;width:${s}px;height:${s}px;` +\n \"object-fit:contain;filter:drop-shadow(0 1px 4px rgba(0,0,0,0.5))\";\n dot.style.cssText = \"display:none\";\n arrow.style.cssText = \"display:none\";\n return;\n }\n img.onerror = null;\n if (img.getAttribute(\"src\") !== null) img.removeAttribute(\"src\");\n img.style.cssText = \"display:none\";\n dot.style.cssText =\n `position:absolute;inset:0;border-radius:50%;background:${puck.color};` +\n \"border:2px solid #ffffff;box-shadow:0 1px 6px rgba(0,0,0,0.45)\";\n arrow.style.cssText = puck.headingArrow\n ? `position:absolute;left:50%;top:${(-s * 0.55).toFixed(1)}px;transform:translateX(-50%);` +\n `width:0;height:0;border-left:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-right:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-bottom:${(s * 0.6).toFixed(1)}px solid ${puck.color}`\n : \"display:none\";\n}\n","/**\n * PlacesLayer - drop your own places (store locations, depots, POIs) onto a\n * MapMap map: the store-finder use case.\n *\n * A GeoJSON source plus MapLibre layers, following the RouteLayer pattern:\n * native clustering (`cluster: true` on the source) with count badges,\n * click-to-expand clusters, a typed `onPlaceClick` callback and an optional\n * built-in popup, plus pure `nearest()` (haversine) and gateway-backed\n * `nearestByDriveTime()` (`POST /matrix`) helpers for \"which branch is\n * closest?\".\n *\n * Like RouteLayer, the layer survives `setStyle` (light/dark theme swaps):\n * places are re-installed on every `style.load`.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n CircleLayerSpecification,\n GeoJSONSource,\n MapLayerMouseEvent,\n Map as MlMap,\n Popup,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\n\n/** Mean Earth radius in metres (IUGG), as used by turf and PostGIS. */\nconst EARTH_RADIUS_M = 6371008.8;\n/** Font stack for cluster-count badges; ships with the MapMap default styles. */\nconst CLUSTER_TEXT_FONT = \"Noto Sans Regular\";\n\n/** One place to show on the map - a store, depot, branch, POI. */\nexport interface Place {\n /** Stable unique id, e.g. your store number. */\n id: string;\n /** Display name. */\n name: string;\n /** Latitude, degrees. */\n lat: number;\n /** Longitude, degrees. */\n lon: number;\n /**\n * Arbitrary extra data (opening hours, phone, …). Copied onto the GeoJSON\n * feature properties, so it is available to data-driven styling and comes\n * back on the place handed to `onPlaceClick` / `popup`.\n */\n properties?: Record<string, unknown>;\n}\n\n/** A GeoJSON Point feature, as accepted in a {@link PlacesFeatureCollection}. */\nexport interface PlacePointFeature {\n type: \"Feature\";\n id?: string | number;\n geometry: { type: \"Point\"; coordinates: number[] };\n properties?: Record<string, unknown> | null;\n}\n\n/**\n * A plain GeoJSON FeatureCollection of Points, accepted anywhere a `Place[]`\n * is (structurally compatible with `@types/geojson`'s\n * `FeatureCollection<Point>`). See {@link placesFromGeoJSON} for how ids and\n * names are derived.\n */\nexport interface PlacesFeatureCollection {\n type: \"FeatureCollection\";\n features: PlacePointFeature[];\n}\n\n/** Either input shape for {@link PlacesLayer} / `setPlaces`. */\nexport type PlacesInput = Place[] | PlacesFeatureCollection;\n\n/** A place with its straight-line distance attached (see `nearest`). */\nexport type PlaceWithDistance = Place & {\n /** Straight-line (haversine) distance from the origin, metres. */\n distanceM: number;\n};\n\n/** A place with gateway drive time attached (see `nearestByDriveTime`). */\nexport type PlaceWithDriveTime = Place & {\n /** Drive time from the origin, seconds. */\n durationS: number;\n /** Driven distance from the origin, metres (`null` when not returned). */\n distanceM: number | null;\n};\n\n/** A custom pin image for unclustered places. */\nexport interface PlacesIcon {\n /** Image URL (any format `Map#loadImage` accepts, e.g. PNG). */\n url: string;\n /** MapLibre `icon-size` scale factor. Defaults to `1`. */\n size?: number;\n}\n\n/** Options for {@link PlacesLayer.nearestByDriveTime}. */\nexport interface NearestByDriveTimeOptions {\n /** How many places to return. Defaults to `1`. */\n n?: number;\n /**\n * Gateway costing model, e.g. `\"auto\"` (default) or `\"truck\"` (Premium\n * price class - see `POST /matrix` in the API docs).\n */\n costing?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ truck: { height: 4.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface PlacesLayerOptions {\n /** Initial places. Also settable later via {@link PlacesLayer.setPlaces}. */\n places?: PlacesInput;\n /** Cluster nearby places into count badges. Defaults to `true`. */\n cluster?: boolean;\n /** Cluster radius in pixels. Defaults to MapLibre's `50`. */\n clusterRadius?: number;\n /** Max zoom to cluster at. Defaults to MapLibre's `14`. */\n clusterMaxZoom?: number;\n /** Pin and cluster colour. Defaults to MapMap signal blue (`#3a86ff`). */\n color?: string;\n /**\n * Custom pin image for unclustered places (a symbol layer instead of the\n * default circle). If the image fails to load, the circle look is used.\n */\n icon?: PlacesIcon;\n /**\n * Fit the map to the places the first time they are set. Defaults to\n * `false` (the map view is left alone).\n */\n fitBounds?: boolean;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-places\"`. */\n id?: string;\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Called when an individual (unclustered) place is clicked. */\n onPlaceClick?: (place: Place, lngLat: { lng: number; lat: number }) => void;\n /**\n * Built-in popup: return HTML (a string is set with `setHTML`, an element\n * with `setDOMContent`) and a `maplibregl.Popup` opens at the place on\n * click. Omit for no popup.\n */\n popup?: (place: Place) => string | HTMLElement;\n}\n\n/**\n * Normalise a GeoJSON FeatureCollection of Points to `Place[]`. The id comes\n * from `feature.id`, then `properties.id`, then the feature index; the name\n * from `properties.name` (else `\"\"`). Non-Point features are skipped.\n */\nexport function placesFromGeoJSON(\n collection: PlacesFeatureCollection,\n): Place[] {\n const places: Place[] = [];\n collection.features.forEach((feature, index) => {\n if (feature.geometry?.type !== \"Point\") return;\n const [lon, lat] = feature.geometry.coordinates;\n if (typeof lon !== \"number\" || typeof lat !== \"number\") {\n throw new Error(`place feature ${index} has no [lon, lat] coordinates`);\n }\n const props = feature.properties ?? {};\n const rawId = feature.id ?? props[\"id\"];\n const place: Place = {\n id:\n typeof rawId === \"string\" || typeof rawId === \"number\"\n ? String(rawId)\n : String(index),\n name: typeof props[\"name\"] === \"string\" ? props[\"name\"] : \"\",\n lat,\n lon,\n };\n if (feature.properties) place.properties = feature.properties;\n places.push(place);\n });\n return places;\n}\n\n/** Straight-line (haversine) distance between two points, metres. */\nexport function haversineDistanceM(\n a: { lat: number; lon: number },\n b: { lat: number; lon: number },\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b.lat - a.lat);\n const dLon = rad(b.lon - a.lon);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The GeoJSON built for the source; one Point feature per place. */\ninterface PlacesSourceData {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: \"Point\"; coordinates: [number, number] };\n properties: Record<string, unknown>;\n }[];\n}\n\n/** Draws customer places on a MapLibre map, with clustering and popups. */\nexport class PlacesLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string | undefined;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly clustersLayerId: string;\n private readonly clusterCountLayerId: string;\n private readonly pointsLayerId: string;\n private readonly iconImageId: string;\n private readonly cluster: boolean;\n private readonly clusterRadius: number | undefined;\n private readonly clusterMaxZoom: number | undefined;\n private readonly color: string;\n private readonly icon: PlacesIcon | undefined;\n private readonly wantFitBounds: boolean;\n private readonly onPlaceClick:\n | ((place: Place, lngLat: { lng: number; lat: number }) => void)\n | undefined;\n private readonly popupFn:\n | ((place: Place) => string | HTMLElement)\n | undefined;\n private places: Place[] = [];\n private data: PlacesSourceData | undefined;\n private popup: Popup | undefined;\n private fitted = false;\n private destroyed = false;\n\n constructor(map: MapMapMap | MlMap, options: PlacesLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n this.baseUrl = options.baseUrl?.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-places\";\n this.sourceId = `${id}-src`;\n this.clustersLayerId = `${id}-clusters`;\n this.clusterCountLayerId = `${id}-cluster-count`;\n this.pointsLayerId = `${id}-points`;\n this.iconImageId = `${id}-icon`;\n this.cluster = options.cluster ?? true;\n this.clusterRadius = options.clusterRadius;\n this.clusterMaxZoom = options.clusterMaxZoom;\n this.color = options.color ?? SIGNAL_BLUE;\n this.icon = options.icon;\n this.wantFitBounds = options.fitBounds ?? false;\n this.onPlaceClick = options.onPlaceClick;\n this.popupFn = options.popup;\n\n // Same lifecycle as RouteLayer: runtime sources/layers are wiped on\n // every setStyle (theme swap), so re-install on each style.load - which\n // also completes a setPlaces that arrived before the style had loaded.\n this.map.on(\"style.load\", this.handleStyleLoad);\n // Delegated layer events survive layer re-installation (they are bound\n // to the layer id, not the layer object), so bind them once here.\n this.map.on(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.on(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.on(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.on(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n\n if (options.places) this.setPlaces(options.places);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.data) this.install(this.data);\n };\n\n private readonly handleMouseEnter = (): void => {\n this.map.getCanvas().style.cursor = \"pointer\";\n };\n\n private readonly handleMouseLeave = (): void => {\n this.map.getCanvas().style.cursor = \"\";\n };\n\n private readonly handlePlaceClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const index: unknown = feature.properties?.[\"__mapmapIndex\"];\n if (typeof index !== \"number\") return;\n const place = this.places[index];\n if (!place) return;\n this.onPlaceClick?.(place, { lng: e.lngLat.lng, lat: e.lngLat.lat });\n if (this.popupFn) this.openPopup(place);\n };\n\n private readonly handleClusterClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const clusterId: unknown = feature.properties?.[\"cluster_id\"];\n if (typeof clusterId !== \"number\") return;\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (!source) return;\n const geometry = feature.geometry;\n if (geometry.type !== \"Point\") return;\n const [lng, lat] = geometry.coordinates;\n if (typeof lng !== \"number\" || typeof lat !== \"number\") return;\n void source\n .getClusterExpansionZoom(clusterId)\n .then((zoom) => {\n if (!this.destroyed) this.map.easeTo({ center: [lng, lat], zoom });\n })\n .catch(() => {\n /* cluster no longer in the source (data changed mid-flight) */\n });\n };\n\n /**\n * Replace the layer's places - a `Place[]` or a GeoJSON FeatureCollection\n * of Points. Updates the existing GeoJSON source in place; safe to call\n * before the style has loaded (installed on the next `style.load`). With\n * `fitBounds: true` the first non-empty set also fits the map view.\n */\n setPlaces(places: PlacesInput): void {\n this.places = Array.isArray(places) ? places : placesFromGeoJSON(places);\n this.data = {\n type: \"FeatureCollection\",\n features: this.places.map((place, index) => ({\n type: \"Feature\",\n geometry: { type: \"Point\", coordinates: [place.lon, place.lat] },\n properties: {\n ...place.properties,\n id: place.id,\n name: place.name,\n __mapmapIndex: index,\n },\n })),\n };\n if (this.wantFitBounds && !this.fitted && this.places.length > 0) {\n this.fitted = true;\n this.map.fitBounds(boundsOf(this.places), { padding: 48, maxZoom: 15 });\n }\n if (!this.map.isStyleLoaded()) return; // installed by handleStyleLoad\n this.install(this.data);\n }\n\n /** The layer's current places (normalised to `Place[]`). */\n get current(): Place[] {\n return this.places;\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by straight-line\n * (haversine) distance, each with `distanceM` attached. Pure and instant -\n * no network. For road-network answers use {@link nearestByDriveTime}.\n */\n nearest(origin: { lat: number; lon: number }, n = 1): PlaceWithDistance[] {\n return this.places\n .map((place) => ({ ...place, distanceM: haversineDistanceM(origin, place) }))\n .sort((a, b) => a.distanceM - b.distanceM)\n .slice(0, Math.max(0, n));\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by drive time, via the\n * gateway's `POST /matrix` (one source, all places as targets). Resolves\n * to places sorted by `durationS` ascending, with the driven `distanceM`\n * attached; unreachable places (`null` duration) are dropped. Needs the\n * gateway `baseUrl`/`apiKey` - picked up from a `MapMapMap` automatically,\n * or pass them as layer options.\n */\n async nearestByDriveTime(\n origin: { lat: number; lon: number },\n options: NearestByDriveTimeOptions = {},\n ): Promise<PlaceWithDriveTime[]> {\n if (!this.baseUrl) {\n throw new Error(\n \"PlacesLayer needs a baseUrl (or a MapMapMap) for nearestByDriveTime\",\n );\n }\n if (this.places.length === 0) return [];\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n const body: Record<string, unknown> = {\n sources: [{ lat: origin.lat, lon: origin.lon }],\n targets: this.places.map((p) => ({ lat: p.lat, lon: p.lon })),\n costing: options.costing ?? \"auto\",\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const response = await fetch(`${this.baseUrl}/matrix`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `matrix request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n const { durations, distances } = matrixRows(payload);\n\n const reachable: PlaceWithDriveTime[] = [];\n this.places.forEach((place, index) => {\n const durationS = durations[index];\n if (typeof durationS !== \"number\") return; // null = unreachable\n const distanceM = distances?.[index];\n reachable.push({\n ...place,\n durationS,\n distanceM: typeof distanceM === \"number\" ? distanceM : null,\n });\n });\n reachable.sort((a, b) => a.durationS - b.durationS);\n return reachable.slice(0, Math.max(0, options.n ?? 1));\n }\n\n /** Add-or-update the source and layers on the current style. */\n private install(data: PlacesSourceData): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data,\n cluster: this.cluster,\n ...(this.cluster && this.clusterRadius !== undefined\n ? { clusterRadius: this.clusterRadius }\n : {}),\n ...(this.cluster && this.clusterMaxZoom !== undefined\n ? { clusterMaxZoom: this.clusterMaxZoom }\n : {}),\n });\n }\n\n if (this.cluster) this.installClusterLayers();\n this.installPointsLayer();\n }\n\n /** Cluster circles (sized by count) and the count badge on top. */\n private installClusterLayers(): void {\n if (!this.map.getLayer(this.clustersLayerId)) {\n const clusters: CircleLayerSpecification = {\n id: this.clustersLayerId,\n type: \"circle\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n paint: {\n \"circle-color\": this.color,\n \"circle-opacity\": 0.9,\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 16, 25, 20, 100, 26],\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(clusters);\n }\n if (!this.map.getLayer(this.clusterCountLayerId)) {\n const count: SymbolLayerSpecification = {\n id: this.clusterCountLayerId,\n type: \"symbol\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n layout: {\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-font\": [CLUSTER_TEXT_FONT],\n \"text-size\": 12,\n },\n paint: { \"text-color\": \"#ffffff\" },\n };\n this.map.addLayer(count);\n }\n }\n\n /**\n * The unclustered-places layer: a circle pin by default, or a symbol\n * layer once the custom `icon` image has loaded (falling back to the\n * circle look if it fails, like PositionPuck's image fallback).\n */\n private installPointsLayer(): void {\n if (this.map.getLayer(this.pointsLayerId)) return;\n if (!this.icon) {\n this.addCirclePointsLayer();\n return;\n }\n if (this.map.hasImage(this.iconImageId)) {\n this.addIconPointsLayer();\n return;\n }\n void this.map\n .loadImage(this.icon.url)\n .then((image) => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n if (!this.map.hasImage(this.iconImageId)) {\n this.map.addImage(this.iconImageId, image.data);\n }\n this.addIconPointsLayer();\n })\n .catch(() => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n this.addCirclePointsLayer();\n });\n }\n\n private addCirclePointsLayer(): void {\n const points: CircleLayerSpecification = {\n id: this.pointsLayerId,\n type: \"circle\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n paint: {\n \"circle-color\": this.color,\n \"circle-radius\": 7,\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(points);\n }\n\n private addIconPointsLayer(): void {\n const points: SymbolLayerSpecification = {\n id: this.pointsLayerId,\n type: \"symbol\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n layout: {\n \"icon-image\": this.iconImageId,\n \"icon-size\": this.icon?.size ?? 1,\n \"icon-allow-overlap\": true,\n },\n };\n this.map.addLayer(points);\n }\n\n /** Open the built-in popup for a place, replacing any previous one. */\n private openPopup(place: Place): void {\n if (!this.popupFn) return;\n const content = this.popupFn(place);\n const popup = new maplibregl.Popup({ offset: 12 }).setLngLat([\n place.lon,\n place.lat,\n ]);\n if (typeof content === \"string\") popup.setHTML(content);\n else popup.setDOMContent(content);\n this.popup?.remove();\n this.popup = popup.addTo(this.map);\n }\n\n /** Remove the places' layers, source, image and popup from the map. */\n clear(): void {\n this.popup?.remove();\n this.popup = undefined;\n for (const layerId of [\n this.pointsLayerId,\n this.clusterCountLayerId,\n this.clustersLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n if (this.map.hasImage(this.iconImageId)) {\n this.map.removeImage(this.iconImageId);\n }\n this.places = [];\n this.data = undefined;\n }\n\n /**\n * Remove the places and detach every listener (style.load, clicks,\n * hovers). Call when disposing of the layer (the map is left untouched).\n */\n destroy(): void {\n this.destroyed = true;\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.map.off(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.off(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.off(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.off(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n this.clear();\n }\n}\n\n/** Bounding box of a non-empty place list, as MapLibre `fitBounds` corners. */\nfunction boundsOf(\n places: Place[],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const { lon, lat } of places) {\n if (lon < minLng) minLng = lon;\n if (lat < minLat) minLat = lat;\n if (lon > maxLng) maxLng = lon;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n/**\n * Pull the origin's rows out of a `POST /matrix` response\n * (`{\"durations\": [[…]], \"distances\": [[…]]}`, row-major, one row here\n * because we send a single source). Throws on anything else.\n */\nfunction matrixRows(payload: unknown): {\n durations: (number | null)[];\n distances: (number | null)[] | undefined;\n} {\n if (typeof payload !== \"object\" || payload === null) {\n throw new Error(\"matrix returned a non-object response\");\n }\n const obj = payload as Record<string, unknown>;\n const durations = firstRow(obj[\"durations\"]);\n if (!durations) {\n throw new Error(\"matrix response has no durations row\");\n }\n return { durations, distances: firstRow(obj[\"distances\"]) };\n}\n\n/** The first row of a row-major `(number | null)[][]`, if that is the shape. */\nfunction firstRow(value: unknown): (number | null)[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const row: unknown = value[0];\n if (!Array.isArray(row)) return undefined;\n return row.map((cell: unknown) =>\n typeof cell === \"number\" && Number.isFinite(cell) ? cell : null,\n );\n}\n","/**\n * NavigationCamera - the turnkey chase-cam for turn-by-turn navigation.\n *\n * Packages the Google-Maps-style follow camera on top of MapLibre's native\n * camera: per-fix `easeTo` with linear easing (continuous glide, no\n * rubber-banding), course-up bearing, a tilted pitch preset, and a\n * screen-offset that anchors the puck low-centre so the camera looks ahead.\n * User gestures (drag, rotate, pitch, zoom) switch the camera to `\"free\"`\n * mode; it auto-recentres after a configurable idle period. An `overview()`\n * mode fits the whole route top-down, and `resume()` returns to the chase\n * cam at the last known fix.\n *\n * Like `RouteLayer`, the class holds only a structural handle on the map\n * (`easeTo`, `fitBounds`, `stop`, events, container) so it is unit-testable\n * against a fake without a WebGL context.\n *\n * Globe projection note: {@link NavigationCamera.isSupported} returns\n * `false` when the map runs the globe (or vertical-perspective) projection.\n * At navigation zooms globe renders much like mercator, but the pixel-offset\n * anchor maths and the top-down overview framing assume a mercator camera;\n * switch the map to mercator (`map.setProjection({ type: \"mercator\" })`)\n * before navigating, or accept an unanchored follow.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport type { PositionPuck } from \"./puck.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n/** A GPS fix to follow. */\nexport interface CameraFix {\n lat: number;\n lon: number;\n}\n\n/** The camera's current behaviour. */\nexport type NavigationCameraMode = \"follow\" | \"overview\" | \"free\";\n\nexport interface NavigationCameraOptions {\n /**\n * Camera tilt in degrees, clamped to 0-85. Default `60` - MapLibre's\n * non-experimental ceiling; values above 60 may show rendering artefacts\n * and flatten DOM-marker pucks. When the requested pitch exceeds the\n * map's `maxPitch`, the limit is raised to match.\n *\n * Precedence: this option > the Studio design's `camera.pitch` (when the\n * map is a `MapMapMap` whose theme carried `extra.nav.camera`) > the\n * built-in default.\n */\n pitch?: number;\n /**\n * Follow-mode zoom. Default `17`. Same precedence as `pitch`: option >\n * Studio design `camera.zoom` > built-in default.\n */\n zoom?: number;\n /**\n * Where the fix (and puck) sits vertically on screen, as a fraction of\n * the container height from the top, clamped to 0-1. Default `0.72` -\n * the puck rides low so the camera looks up the road ahead.\n */\n anchorY?: number;\n /**\n * Ease duration per {@link NavigationCamera.follow} call, milliseconds.\n * Default `900`, and always capped by the observed fix interval so a\n * fast fix cadence never queues up lagging animations.\n */\n easeMs?: number;\n /**\n * Idle time after the last user gesture before the camera recentres\n * itself back to follow mode, milliseconds. Default `6000`; `0` disables\n * auto-recentre (the app must call {@link NavigationCamera.resume}).\n */\n autoRecentreMs?: number;\n}\n\n/** The map-interaction events that hand the camera to the user. */\nconst INTERACTION_EVENTS = [\n \"dragstart\",\n \"rotatestart\",\n \"pitchstart\",\n \"zoomstart\",\n] as const;\n\nconst DEFAULT_PITCH = 60;\nconst DEFAULT_ZOOM = 17;\nconst DEFAULT_ANCHOR_Y = 0.72;\nconst DEFAULT_EASE_MS = 900;\nconst DEFAULT_AUTO_RECENTRE_MS = 6000;\n/** Screen padding around the route in overview mode, pixels. */\nconst OVERVIEW_PADDING_PX = 48;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Anything with a `PositionPuck`-shaped `setLocation` can be co-driven. */\ntype CoDrivenPuck = Pick<PositionPuck, \"setLocation\">;\n\n/** A follow-mode chase camera for MapMap maps. */\nexport class NavigationCamera {\n private readonly m: MlMap;\n private readonly pitch: number;\n private readonly zoom: number;\n private readonly anchorY: number;\n private readonly easeMs: number;\n private readonly autoRecentreMs: number;\n\n private currentMode: NavigationCameraMode = \"follow\";\n private puck: CoDrivenPuck | undefined;\n private lastFix: CameraFix | undefined;\n private lastCourse: number | undefined;\n private lastFixAt: number | undefined;\n private lastRoute: RouteGeometry | undefined;\n private recentreTimer: ReturnType<typeof setTimeout> | undefined;\n private destroyed = false;\n\n // Bound once so `off` in destroy() removes exactly what `on` added.\n private readonly onInteraction = (ev?: { originalEvent?: unknown }): void => {\n // Camera-driven moves (our own easeTo/fitBounds) fire the same events\n // without an `originalEvent`; only real user gestures carry one.\n if (!ev?.originalEvent || this.destroyed) return;\n this.currentMode = \"free\";\n this.m.stop();\n this.scheduleRecentre();\n };\n\n /**\n * `false` when the map runs the globe (or vertical-perspective)\n * projection, whose camera geometry breaks the low-anchor offset maths\n * and top-down overview framing. Switch to mercator for navigation.\n */\n static isSupported(map: MapMapMap | MlMap): boolean {\n const m = map instanceof MapMapMap ? map.map : map;\n const projection = (\n m as { getProjection?: () => unknown }\n ).getProjection?.();\n return !usesGlobe(projection);\n }\n\n constructor(map: MapMapMap | MlMap, options: NavigationCameraOptions = {}) {\n this.m = map instanceof MapMapMap ? map.map : map;\n // A MapMapMap built from a Studio theme may carry `extra.nav.camera`;\n // its pitch/zoom become the option defaults. Precedence: explicit\n // option > design > built-in default.\n const design = map instanceof MapMapMap ? map.navDesign?.camera : undefined;\n this.pitch = clamp(options.pitch ?? design?.pitch ?? DEFAULT_PITCH, 0, 85);\n this.zoom = options.zoom ?? design?.zoom ?? DEFAULT_ZOOM;\n this.anchorY = clamp(options.anchorY ?? DEFAULT_ANCHOR_Y, 0, 1);\n this.easeMs = Math.max(0, options.easeMs ?? DEFAULT_EASE_MS);\n this.autoRecentreMs = Math.max(\n 0,\n options.autoRecentreMs ?? DEFAULT_AUTO_RECENTRE_MS,\n );\n\n // A pitch preset above the map's ceiling would be silently clamped by\n // MapLibre; raise the ceiling to honour the preset (never lower it).\n if (this.pitch > this.m.getMaxPitch()) this.m.setMaxPitch(this.pitch);\n\n for (const event of INTERACTION_EVENTS) {\n this.m.on(event, this.onInteraction);\n }\n }\n\n /** The camera's current behaviour: `\"follow\"`, `\"overview\"` or `\"free\"`. */\n get mode(): NavigationCameraMode {\n return this.currentMode;\n }\n\n /**\n * Co-drive a {@link PositionPuck}: every {@link follow} call also\n * `setLocation`s the puck, so camera and puck never diverge.\n */\n attachPuck(puck: CoDrivenPuck): void {\n this.puck = puck;\n }\n\n /**\n * Glide the camera to a fix, course-up when `courseDeg` is given\n * (bearing is left unchanged when it is `undefined`). Each call eases\n * with linear timing over `easeMs` capped by the observed fix interval,\n * and interrupts the previous ease (no queue buildup). The fix and an\n * attached puck are always updated, but the camera only moves in\n * `\"follow\"` mode - `\"free\"` and `\"overview\"` record the fix for\n * {@link resume}.\n */\n follow(fix: CameraFix, courseDeg?: number): void {\n const now = Date.now();\n const interval =\n this.lastFixAt === undefined\n ? this.easeMs\n : Math.max(0, now - this.lastFixAt);\n this.lastFixAt = now;\n this.lastFix = fix;\n if (courseDeg !== undefined) this.lastCourse = courseDeg;\n this.puck?.setLocation(fix, courseDeg);\n if (this.currentMode !== \"follow\") return;\n this.easeToFix(fix, courseDeg, Math.min(this.easeMs, interval));\n }\n\n /**\n * Fit the route top-down (pitch 0, north-up). Pass the route geometry on\n * the first call; later calls reuse the last geometry given. A no-op\n * when no geometry has ever been provided.\n */\n overview(routeGeometry?: RouteGeometry): void {\n if (routeGeometry) this.lastRoute = routeGeometry;\n const route = this.lastRoute;\n if (!route || route.coordinates.length === 0) return;\n this.clearRecentreTimer();\n this.currentMode = \"overview\";\n this.m.fitBounds(boundsOf(route.coordinates), {\n padding: OVERVIEW_PADDING_PX,\n pitch: 0,\n bearing: 0,\n duration: this.easeMs,\n essential: true,\n });\n }\n\n /**\n * Return to follow mode, gliding back to the last fix (with its last\n * known course) when one has been recorded.\n */\n resume(): void {\n this.clearRecentreTimer();\n this.currentMode = \"follow\";\n if (this.lastFix) {\n this.easeToFix(this.lastFix, this.lastCourse, this.easeMs);\n }\n }\n\n /** Remove the map listeners and cancel any pending auto-recentre. */\n destroy(): void {\n this.destroyed = true;\n this.clearRecentreTimer();\n for (const event of INTERACTION_EVENTS) {\n this.m.off(event, this.onInteraction);\n }\n }\n\n private easeToFix(\n fix: CameraFix,\n courseDeg: number | undefined,\n duration: number,\n ): void {\n this.m.easeTo({\n center: [fix.lon, fix.lat],\n ...(courseDeg !== undefined ? { bearing: courseDeg } : {}),\n pitch: this.pitch,\n zoom: this.zoom,\n offset: [0, this.anchorOffsetY()],\n duration,\n easing: (t: number) => t,\n // Interrupt semantics: `essential` easings run even under\n // prefers-reduced-motion, and each new easeTo cancels the previous\n // one, so a fast fix cadence glides instead of queueing.\n essential: true,\n });\n }\n\n /**\n * The pixel offset that renders the followed fix at `anchorY` of the\n * container height: `(anchorY - 0.5) * height` (0.5 is the natural\n * centre; positive y moves the puck down the screen).\n */\n private anchorOffsetY(): number {\n const height = this.m.getContainer().clientHeight;\n return (this.anchorY - 0.5) * height;\n }\n\n private scheduleRecentre(): void {\n this.clearRecentreTimer();\n if (this.autoRecentreMs === 0) return;\n this.recentreTimer = setTimeout(() => {\n this.recentreTimer = undefined;\n if (this.currentMode === \"free\") this.resume();\n }, this.autoRecentreMs);\n }\n\n private clearRecentreTimer(): void {\n if (this.recentreTimer !== undefined) {\n clearTimeout(this.recentreTimer);\n this.recentreTimer = undefined;\n }\n }\n}\n\n/** South-west / north-east bounds of a coordinate list. */\nfunction boundsOf(\n coordinates: [number, number][],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const [lng, lat] of coordinates) {\n if (lng < minLng) minLng = lng;\n if (lng > maxLng) maxLng = lng;\n if (lat < minLat) minLat = lat;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n/**\n * Whether a `getProjection()` result names the globe. MapLibre v5 returns\n * `{ type }` where `type` is `\"globe\"`, `\"mercator\"`,\n * `\"vertical-perspective\"` or a style expression that can evaluate to any\n * of them; any mention of globe/vertical-perspective counts as globe.\n */\nfunction usesGlobe(projection: unknown): boolean {\n if (projection === null || projection === undefined) return false;\n if (typeof projection === \"string\") {\n return projection === \"globe\" || projection === \"vertical-perspective\";\n }\n if (Array.isArray(projection)) return projection.some(usesGlobe);\n if (typeof projection === \"object\") {\n return Object.values(projection).some(usesGlobe);\n }\n return false;\n}\n","/**\n * AdrCheck - optional helper for the gateway's `POST /adr/check` endpoint.\n *\n * The ADR 8.6.4 tunnel compliance engine, exposed directly. No MapLibre\n * dependency; just a typed fetch wrapper.\n */\nimport type { AdrCheckRequest, AdrCheckResult } from \"./types.js\";\n\n/**\n * Builds the exact wire body the gateway deserialises\n * (`sn-gateway` `routes/adr.rs` → `sn_adr::AdrVehicleProfile`):\n * `{\"adr\": {\"dimensions\": {…}, \"tunnel_code\"?, \"hazmat\"}, \"tunnel_category\"}`.\n * Unset dimensions default to the EU 96/53/EC artic maximums, mirroring\n * `TruckDimensions::default()`. Exported for contract tests.\n */\nexport function buildAdrCheckBody(request: AdrCheckRequest): Record<string, unknown> {\n const dims = request.dimensions ?? {};\n const adr: Record<string, unknown> = {\n dimensions: {\n height_m: dims.heightM ?? 4.0,\n width_m: dims.widthM ?? 2.55,\n length_m: dims.lengthM ?? 16.5,\n gross_weight_t: dims.grossWeightT ?? 40.0,\n axle_load_t: dims.axleLoadT ?? null,\n axle_count: dims.axleCount ?? null,\n },\n hazmat: request.hazmat,\n };\n // Omitted entirely when unknown: the gateway reads a missing tunnel_code\n // as \"dangerous goods of unknown code\" (conservative code-B fallback).\n if (request.tunnelCode !== undefined) adr[\"tunnel_code\"] = request.tunnelCode;\n return { adr, tunnel_category: request.tunnelCategory };\n}\n\nexport interface AdrCheckOptions {\n /** Gateway base URL, e.g. `https://api.mapmap.ai`. */\n baseUrl: string;\n /** Gateway API key (`snk_…`). */\n apiKey?: string;\n}\n\n/** Calls `POST /adr/check` and returns the parsed compliance decision. */\nexport class AdrCheck {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n\n constructor(options: AdrCheckOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n async check(request: AdrCheckRequest): Promise<AdrCheckResult> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/adr/check`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(buildAdrCheckBody(request)),\n });\n\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `ADR check failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"ADR check returned a non-object response\");\n }\n const obj = body as Record<string, unknown>;\n const result: AdrCheckResult = {\n status: typeof obj[\"status\"] === \"string\" ? obj[\"status\"] : \"unknown\",\n raw: obj,\n };\n if (typeof obj[\"reason\"] === \"string\") result.reason = obj[\"reason\"];\n return result;\n }\n}\n","/**\n * Turn-by-turn guidance helpers: voice + banner instructions and lanes.\n *\n * The gateway's OSRM endpoint returns Mapbox-shaped `voiceInstructions`\n * (plain + SSML announcements with distance triggers) and\n * `bannerInstructions` (primary line with a maneuver glyph, lane\n * sub-banners) on each step when requested with\n * `voice: true` / `banner: true` route options. This module extracts them\n * from a parsed route, renders a banner as a DOM element, and speaks\n * announcements through the browser's `SpeechSynthesis`.\n *\n * Everything except {@link GuidanceBanner} and {@link speak} is pure and\n * covered by unit tests.\n */\n\nimport type { NavBannerDesign } from \"./nav-design.js\";\nimport type { ParsedRoute } from \"./types.js\";\n\n/** A spoken instruction with its trigger distance before the maneuver. */\nexport interface VoiceInstruction {\n /** Metres before the end of the step at which to announce. */\n distanceAlongGeometry: number;\n /** Plain text for speech synthesis. */\n announcement: string;\n /** SSML form, preferred by engines that support it. */\n ssmlAnnouncement?: string;\n}\n\n/** One lane entry of a banner lane diagram. */\nexport interface LaneIndication {\n /** Turn directions this lane allows (OSRM indication strings). */\n directions: string[];\n /**\n * Whether the lane can be used for the maneuver. `undefined` means\n * unknown, not unusable — banner components omit the flag for\n * non-recommended lanes (see {@link bannerLanes}).\n */\n valid?: boolean;\n /** Whether guidance recommends this lane. */\n active?: boolean;\n}\n\n/** A typed fragment of banner content. */\nexport interface BannerComponent {\n type: string;\n text: string;\n directions?: string[];\n active?: boolean;\n}\n\n/** One banner line. */\nexport interface BannerContent {\n text: string;\n type?: string;\n modifier?: string;\n components?: BannerComponent[];\n}\n\n/** The visual banner shown while travelling a step. */\nexport interface BannerInstruction {\n distanceAlongGeometry: number;\n primary: BannerContent;\n secondary?: BannerContent;\n sub?: BannerContent;\n}\n\n/** Guidance data for one step of the route. */\nexport interface StepGuidance {\n /** Step index within the flattened route. */\n stepIndex: number;\n /** Step length in metres. */\n distanceM: number;\n /**\n * Written instruction for the step's upcoming maneuver. Taken from\n * `maneuver.instruction` when a server emits it (Mapbox-style); the\n * MapMap gateway does not, so it falls back to the step's final voice\n * announcement (the pre-transition instruction) and then to the banner\n * primary text. Undefined only when the step carries no guidance at all.\n */\n instruction?: string;\n /** Spoken announcements, ordered by descending trigger distance. */\n voice: VoiceInstruction[];\n /** Visual banners for the upcoming maneuver. */\n banners: BannerInstruction[];\n}\n\n/**\n * Extracts per-step guidance from a parsed route (requires the route to\n * have been requested with `steps: true` and voice/banner enabled).\n * Steps without instructions yield empty arrays, never holes.\n */\nexport function extractGuidance(route: ParsedRoute): StepGuidance[] {\n const legs = (route.raw[\"legs\"] as Record<string, unknown>[] | undefined) ?? [];\n const out: StepGuidance[] = [];\n let index = 0;\n for (const leg of legs) {\n const steps = (leg[\"steps\"] as Record<string, unknown>[] | undefined) ?? [];\n for (const step of steps) {\n const voice = (step[\"voiceInstructions\"] as VoiceInstruction[] | undefined) ?? [];\n const banners = (step[\"bannerInstructions\"] as BannerInstruction[] | undefined) ?? [];\n out.push({\n stepIndex: index,\n distanceM: Number(step[\"distance\"] ?? 0),\n instruction: stepInstruction(step, voice, banners),\n voice,\n banners,\n });\n index += 1;\n }\n }\n return out;\n}\n\n/**\n * The written instruction for a step. The gateway's OSRM translation\n * (`sn-valhalla` `osrm.rs`) emits no `maneuver.instruction`; the written\n * text lives in the voice announcements (the last one is the pre-transition\n * instruction, e.g. \"Turn right onto High Street\") and in the banner\n * primary text. Prefer `maneuver.instruction` when a server does emit it.\n */\nfunction stepInstruction(\n step: Record<string, unknown>,\n voice: VoiceInstruction[],\n banners: BannerInstruction[],\n): string | undefined {\n const maneuver = step[\"maneuver\"] as Record<string, unknown> | undefined;\n const fromManeuver = maneuver?.[\"instruction\"];\n if (typeof fromManeuver === \"string\" && fromManeuver.length > 0) {\n return fromManeuver;\n }\n const lastVoice = voice[voice.length - 1];\n if (\n typeof lastVoice?.announcement === \"string\" &&\n lastVoice.announcement.length > 0\n ) {\n return lastVoice.announcement;\n }\n const bannerText = banners[0]?.primary?.text;\n if (typeof bannerText === \"string\" && bannerText.length > 0) {\n return bannerText;\n }\n return undefined;\n}\n\n/** Named XML entities the gateway's `xml_escape` (and standard SSML) emit. */\nconst XML_ENTITIES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \""\": '\"',\n \"'\": \"'\",\n};\n\n/**\n * Strips SSML tags down to speakable plain text. Entities are decoded in a\n * single pass (never re-scanning already-decoded output), so text whose\n * literal content looks like an entity — e.g. `&lt;`, the gateway's\n * escape of a literal `<` — round-trips correctly. Decodes the five\n * named XML entities plus decimal numeric references (`'`).\n */\nexport function ssmlToText(ssml: string): string {\n return ssml\n .replace(/<[^>]+>/g, \"\")\n .replace(/&(?:amp|lt|gt|quot|apos);|&#(\\d+);/g, (entity, decimal: string | undefined) =>\n decimal !== undefined\n ? String.fromCodePoint(Number(decimal))\n : (XML_ENTITIES[entity] ?? entity),\n )\n .trim();\n}\n\n/**\n * Lane entries of a banner's sub line, if it carries a lane diagram.\n *\n * Banner lane components only carry `active` (the recommended lane) — the\n * gateway drops the per-lane `valid` flag from banners, keeping it in the\n * raw route's `intersections[].lanes`. An active lane is by definition\n * usable, so `valid` is `true` for active lanes and *unknown* (undefined,\n * never `false`) for the rest: a non-recommended lane may still be legal.\n * Read `route.raw` `legs[].steps[].intersections[].lanes` for the full\n * `valid` set.\n */\nexport function bannerLanes(banner: BannerInstruction): LaneIndication[] {\n const components = banner.sub?.components ?? [];\n return components\n .filter((c) => c.type === \"lane\")\n .map((c) => {\n const lane: LaneIndication = { directions: c.directions ?? [] };\n if (c.active !== undefined) lane.active = c.active;\n if (c.active === true) lane.valid = true;\n return lane;\n });\n}\n\n/**\n * Unicode arrow for a lane/maneuver direction (OSRM indication strings).\n * A text-only fallback; sprite-based lane icons ship with the map assets.\n */\nexport function directionArrow(direction: string): string {\n switch (direction) {\n case \"left\":\n return \"←\";\n case \"right\":\n return \"→\";\n case \"straight\":\n case \"none\":\n return \"↑\";\n case \"slight left\":\n return \"↖\";\n case \"slight right\":\n return \"↗\";\n case \"sharp left\":\n return \"↙\";\n case \"sharp right\":\n return \"↘\";\n case \"uturn\":\n return \"↶\";\n case \"merge to left\":\n return \"⬅\";\n case \"merge to right\":\n return \"➡\";\n default:\n return \"•\";\n }\n}\n\n/** Options for {@link speak}. */\nexport interface SpeakOptions {\n /** BCP 47 language for the utterance, e.g. `en-GB`. */\n lang?: string;\n /** Speech rate (0.1–10, default 1). */\n rate?: number;\n}\n\n/**\n * Speaks a voice instruction through the browser's `SpeechSynthesis`.\n * Prefers the SSML body's text (browsers do not accept raw SSML). Returns\n * false when speech synthesis is unavailable (e.g. non-browser contexts).\n * De-duplication is the caller's responsibility: speak each instruction\n * once as its trigger distance is crossed.\n */\nexport function speak(instruction: VoiceInstruction, options: SpeakOptions = {}): boolean {\n const synth = (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n const Utterance = (\n globalThis as {\n SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance;\n }\n ).SpeechSynthesisUtterance;\n if (!synth || !Utterance) return false;\n const text = instruction.ssmlAnnouncement\n ? ssmlToText(instruction.ssmlAnnouncement)\n : instruction.announcement;\n const utterance = new Utterance(text);\n if (options.lang) utterance.lang = options.lang;\n if (options.rate) utterance.rate = options.rate;\n synth.speak(utterance);\n return true;\n}\n\n/**\n * A minimal DOM banner: primary text with a maneuver arrow, optional lane\n * row. Style with the `mapmap-banner` / `mapmap-banner-lanes` classes, pass\n * a Studio design (`extra.nav` `banner` block, e.g. `map.navDesign?.banner`)\n * to match a Studio theme, or read {@link StepGuidance} yourself for fully\n * custom UI.\n */\nexport class GuidanceBanner {\n /** The banner root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavBannerDesign | undefined;\n\n constructor(container?: HTMLElement, design?: NavBannerDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"GuidanceBanner requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-banner\";\n // With a design, the derived metrics follow the Studio preview exactly\n // (gap = padding × 1.2, horizontal padding = padding × 1.4, arrow at\n // fontSize × 1.4, height set = min-height with contents vertically\n // centred, unset = auto). Without one the built-in look is unchanged.\n this.element.style.cssText = design\n ? \"display:none;align-items:center;box-sizing:border-box;\" +\n `gap:${Math.round((design.padding ?? 10) * 1.2)}px;` +\n `padding:${design.padding ?? 10}px ${Math.round((design.padding ?? 10) * 1.4)}px;` +\n `background:${design.background};color:${design.textColor};` +\n `border-radius:${design.cornerRadius ?? 10}px;` +\n `max-width:${design.maxWidth ?? 340}px;` +\n (design.height !== undefined ? `min-height:${design.height}px;` : \"\") +\n `font:600 ${design.fontSize}px/1.3 system-ui,sans-serif`\n : \"display:none;gap:12px;align-items:center;padding:10px 14px;\" +\n \"background:#101418;color:#fff;border-radius:10px;\" +\n \"font:600 16px/1.3 system-ui,sans-serif\";\n container?.appendChild(this.element);\n }\n\n /** Renders a banner instruction (or hides the element with `null`). */\n update(banner: BannerInstruction | null): void {\n if (!banner) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n this.element.style.display = \"flex\";\n\n const arrow = doc.createElement(\"span\");\n arrow.textContent = directionArrow(banner.primary.modifier ?? \"straight\");\n arrow.style.fontSize = this.design\n ? `${Math.round(this.design.fontSize * 1.4)}px`\n : \"22px\";\n\n const text = doc.createElement(\"span\");\n text.textContent = banner.primary.text;\n\n const children: HTMLElement[] = [arrow, text];\n\n const lanes = this.design?.showLanes === false ? [] : bannerLanes(banner);\n if (lanes.length > 0) {\n const laneRow = doc.createElement(\"span\");\n laneRow.className = \"mapmap-banner-lanes\";\n if (this.design) {\n // Studio preview semantics: letter-spacing scales with the padding\n // token, and each lane dims unless guidance recommends it.\n const spacing = Math.max(2, Math.round((this.design.padding ?? 10) * 0.4));\n laneRow.style.cssText = `margin-left:auto;letter-spacing:${spacing}px;white-space:nowrap`;\n for (const lane of lanes) {\n const glyph = doc.createElement(\"span\");\n glyph.textContent = directionArrow(lane.directions[0] ?? \"none\");\n glyph.style.opacity = lane.active ? \"0.95\" : \"0.35\";\n laneRow.appendChild(glyph);\n }\n } else {\n laneRow.style.cssText = \"margin-left:auto;letter-spacing:4px\";\n laneRow.textContent = lanes\n .map((lane) => directionArrow(lane.directions[0] ?? \"none\"))\n .join(\"\");\n laneRow.style.opacity = \"0.9\";\n }\n children.push(laneRow);\n }\n\n this.element.replaceChildren(...children);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/diagnostics.ts","../src/effects.ts","../src/logo.ts","../src/nav-design.ts","../src/poi-design.ts","../src/style.ts","../src/map.ts","../src/coords.ts","../src/osrm.ts","../src/route.ts","../src/puck.ts","../src/places.ts","../src/camera.ts","../src/isochrone.ts","../src/adr.ts","../src/guidance.ts","../src/voice.ts"],"names":["colour","isRecord","lng","lat","maplibregl","EARTH_RADIUS_M","DEFAULT_ZOOM","now","boundsOf","deg","handle","max","fill","synth"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Self-diagnosing map errors - the SDK tells you what went wrong and how\n * to fix it, instead of a silently blank map.\n *\n * `MapMapMap` runs these checks at construction (and listens for tile\n * auth failures); each detected issue produces ONE `console.error` per\n * page with an actionable message and a docs link. Everything here is\n * best-effort and defensive: no check may ever throw or require a DOM\n * (server-side rendering and Node tests just skip the DOM checks).\n *\n * Issues covered - the documented gotchas that burn real integrations:\n * - a container whose height resolves to 0px (MapLibre renders into a\n * 0-tall canvas: no error, no map)\n * - a container element that is not attached to the DOM\n * - two maplibre-gl copies on one page (duplicate dependency /\n * micro-frontends - breaks the shared WebGL context and styles)\n * - WebGL unavailable (headless browsers, blocked GPU, old devices)\n * - missing/invalid API key (a 401 from the tile or routing endpoints)\n */\n\nconst DOCS = \"https://mapmap.ai/docs\";\n\n/** The distinct issues the diagnostics can report. */\nexport type DiagnosticIssue =\n | \"container-zero-height\"\n | \"container-detached\"\n | \"duplicate-maplibre\"\n | \"webgl-unavailable\"\n | \"invalid-api-key\";\n\n/** Issues already reported on this page: one console.error per issue. */\nconst reported = new Set<DiagnosticIssue>();\n\n/**\n * Cross-module registry of maplibre-gl module instances seen on this\n * page. `Symbol.for` + `globalThis` so the registry is shared even when\n * this SDK itself is bundled twice.\n */\nconst MAPLIBRE_REGISTRY_KEY = Symbol.for(\"mapmap.maplibre-instances\");\n\n/** Reset the once-per-page dedup - for tests (and hot-reload tooling). */\nexport function resetDiagnostics(): void {\n reported.clear();\n const holder = globalThis as Record<symbol, unknown>;\n delete holder[MAPLIBRE_REGISTRY_KEY];\n}\n\nfunction report(issue: DiagnosticIssue, message: string): void {\n if (reported.has(issue)) return;\n reported.add(issue);\n console.error(`MapMap [${issue}]: ${message}`);\n}\n\n/** What `runMapDiagnostics` needs; everything optional and structural. */\nexport interface MapDiagnosticsInput {\n /** The `container` option as given: an element or an element id. */\n container?: string | HTMLElement;\n /**\n * The constructed map (or any object with a MapLibre-style `on`). Used\n * to watch for tile-request auth failures.\n */\n map?: unknown;\n /** The maplibre-gl module the SDK is using (duplicate detection). */\n maplibre?: unknown;\n /** The gateway API key, if one was configured. */\n apiKey?: string | undefined;\n}\n\n/** A MapLibre `error` event, structurally. */\ninterface MapErrorEvent {\n error?: { status?: number; message?: string } | undefined;\n}\n\n/**\n * Run the construction-time checks and attach the 401 watcher. Called by\n * `MapMapMap` automatically; exported for apps wrapping a raw\n * `maplibregl.Map` that still want the self-diagnosis.\n */\nexport function runMapDiagnostics(input: MapDiagnosticsInput): void {\n checkDuplicateMaplibre(input.maplibre);\n checkWebgl();\n checkContainer(input.container);\n watchForAuthFailures(input.map, input.apiKey);\n}\n\nfunction checkContainer(container: string | HTMLElement | undefined): void {\n if (container === undefined || typeof document === \"undefined\") return;\n let element: HTMLElement | null;\n try {\n element =\n typeof container === \"string\"\n ? document.getElementById(container)\n : container;\n } catch {\n return;\n }\n if (!element) return; // MapLibre throws its own clear error for this\n // Anything that is not element-shaped is MapLibre's problem to reject.\n if (typeof element.isConnected !== \"boolean\") return;\n if (!element.isConnected) {\n report(\n \"container-detached\",\n \"the map container element is not attached to the DOM, so nothing \" +\n \"can render. Append it to the document before constructing the \" +\n `map. ${DOCS}#container`,\n );\n return; // a detached element always measures 0 - skip the height check\n }\n if (element.clientHeight === 0) {\n report(\n \"container-zero-height\",\n \"the map container's height is 0px, so MapLibre is rendering into \" +\n \"an invisible canvas (no error, no map). Give it a real height, \" +\n `e.g. #map { height: 100vh; }. If the height arrives later (CSS ` +\n `load, layout), you can ignore this. ${DOCS}#container-height`,\n );\n }\n}\n\nfunction checkDuplicateMaplibre(maplibre: unknown): void {\n if (typeof maplibre !== \"object\" && typeof maplibre !== \"function\") return;\n if (maplibre === null) return;\n const holder = globalThis as Record<symbol, unknown>;\n const registry = (holder[MAPLIBRE_REGISTRY_KEY] ??=\n new Set<unknown>()) as Set<unknown>;\n registry.add(maplibre);\n // A UMD copy on window that differs from the module copy counts too.\n const windowCopy = (\n globalThis as { maplibregl?: unknown }\n ).maplibregl;\n if (\n windowCopy !== undefined &&\n (typeof windowCopy === \"object\" || typeof windowCopy === \"function\")\n ) {\n registry.add(windowCopy);\n }\n if (registry.size > 1) {\n report(\n \"duplicate-maplibre\",\n \"two different maplibre-gl instances are loaded on this page \" +\n \"(duplicate dependency, a CDN <script> next to the bundled copy, \" +\n \"or micro-frontends). Maps, styles and the pmtiles protocol \" +\n \"registration will not be shared between them. De-duplicate so \" +\n \"the app owns a single maplibre-gl - it is a peerDependency of \" +\n `@mapmap/maps for exactly this reason. ${DOCS}#duplicate-maplibre`,\n );\n }\n}\n\nfunction checkWebgl(): void {\n if (typeof document === \"undefined\") return;\n try {\n const canvas = document.createElement(\"canvas\");\n const gl =\n canvas.getContext(\"webgl2\") ?? canvas.getContext(\"webgl\");\n if (!gl) {\n report(\n \"webgl-unavailable\",\n \"this browser/environment reports no WebGL support, so the map \" +\n \"cannot render. Common causes: headless browsers without \" +\n \"--use-gl, blocked GPU/hardware acceleration, remote desktops. \" +\n `${DOCS}#webgl`,\n );\n }\n } catch {\n /* probe failure is not evidence either way; stay quiet */\n }\n}\n\nfunction watchForAuthFailures(map: unknown, apiKey: string | undefined): void {\n const on = (map as { on?: (event: string, fn: (ev: MapErrorEvent) => void) => void })\n ?.on;\n if (typeof on !== \"function\" || map === null || map === undefined) return;\n try {\n on.call(map, \"error\", (ev: MapErrorEvent) => {\n const status = ev?.error?.status;\n const message = ev?.error?.message ?? \"\";\n const unauthorised =\n status === 401 || /\\b401\\b|unauthori[sz]ed/i.test(message);\n if (!unauthorised) return;\n report(\n \"invalid-api-key\",\n apiKey\n ? \"the gateway rejected your API key (HTTP 401). Check the \" +\n `\\`apiKey\\` for typos or revocation - keys look like ` +\n `\"snk_…\". ${DOCS}#authentication`\n : \"a request was rejected with HTTP 401 and no `apiKey` was \" +\n \"configured. Pass one to the map (`new MapMapMap({ apiKey: \" +\n '\"snk_…\" })`) - issue a free key with ' +\n `POST https://api.mapmap.ai/v1/keys. ${DOCS}#authentication`,\n );\n });\n } catch {\n /* never let diagnostics break map construction */\n }\n}\n","/**\n * Effects engine - named, geometry-anchored visual effects rendered through\n * MapLibre's stable `CustomLayerInterface` (first-party GLSL, no runtime\n * dependencies). The first effect is `\"flow\"`: an animated energy ribbon\n * along the active route line, drawn as a triangle strip with a flowing\n * pulse gradient driven by a time uniform.\n *\n * Deliberately NOT full-map post-processing: MapLibre has no official\n * post-process hook, so every effect here anchors to geometry and rides the\n * supported custom-layer API. New effects register in {@link ROUTE_EFFECTS}.\n *\n * Accessibility and resilience:\n * - `prefers-reduced-motion: reduce` freezes the ribbon to a static\n * gradient (no animation loop, no repaints).\n * - If WebGL setup for the custom layer fails (shader compile/link, lost\n * context), the effect silently disables itself - the ordinary route\n * line underneath is untouched - and logs a single console warning.\n *\n * The tessellation and colour helpers are pure and unit-tested in Node;\n * only the layer object itself touches WebGL.\n */\nimport type { CustomLayerInterface, Map as MlMap } from \"maplibre-gl\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Kept import-free of route.ts/places.ts on purpose: map.ts imports this\n// module, and both of those import map.ts (cycle), while the pure helpers\n// here must stay loadable in Node without maplibre-gl.\n\n/** MapMap brand signal blue - matches `SIGNAL_BLUE` in route.ts. */\nconst FLOW_COLOUR = \"#3a86ff\";\n\n/** Mean Earth radius in metres (IUGG) - matches places.ts. */\nconst EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction haversineM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The names the effects registry knows. Grows as effects land. */\nexport type RouteEffectName = \"flow\";\n\n/** Options for the `\"flow\"` route effect (all optional). */\nexport interface RouteFlowOptions {\n /** Ribbon colour (hex or rgb()/rgba()). Defaults to MapMap signal blue. */\n color?: string;\n /** Ribbon width in CSS pixels. Defaults to `10`. */\n width?: number;\n /** Flow speed in pulse cycles per second. Defaults to `0.6`. */\n speed?: number;\n /** MapLibre layer id. Defaults to `\"mapmap-route-effect\"`. */\n id?: string;\n}\n\n/** Floats per ribbon vertex: x, y (mercator), nx, ny (unit normal), progress. */\nexport const RIBBON_FLOATS_PER_VERTEX = 5;\n\n/** A tessellated route ribbon, ready for a `TRIANGLE_STRIP` draw. */\nexport interface RibbonMesh {\n /**\n * Interleaved vertex data, {@link RIBBON_FLOATS_PER_VERTEX} floats per\n * vertex: mercator position, the unit extrusion normal (the shader\n * extrudes `pos + normal * halfWidth`, so width stays zoom-correct\n * without re-tessellating), and progress along the route (0 at the\n * start, 1 at the end - the flowing gradient's coordinate).\n */\n vertices: Float32Array;\n /** Number of vertices (two per route point kept). */\n vertexCount: number;\n}\n\n/**\n * Project a `[lng, lat]` to web-mercator world coordinates in [0, 1]\n * (MapLibre's `MercatorCoordinate` convention: x east, y south).\n */\nexport function lngLatToMercator(lngLat: [number, number]): [number, number] {\n const [lng, lat] = lngLat;\n const x = (lng + 180) / 360;\n const y =\n (1 - Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360)) / Math.PI) / 2;\n return [x, y];\n}\n\n/**\n * Tessellate a route line into a centreline triangle strip: two vertices\n * per point, each carrying the point's mercator position, a unit extrusion\n * normal (averaged between adjacent segments at joins - a bevel-free miter\n * that slightly thins very sharp corners, which is invisible on a soft\n * glow ribbon), and normalised progress along the line.\n *\n * Pure: no WebGL, no map. Consecutive duplicate points are dropped; fewer\n * than two distinct points yield an empty mesh.\n */\nexport function tessellateRouteRibbon(\n coordinates: [number, number][],\n): RibbonMesh {\n // Project and drop consecutive duplicates (zero-length segments have no\n // direction and would produce NaN normals).\n const points: [number, number][] = [];\n for (const lngLat of coordinates) {\n const p = lngLatToMercator(lngLat);\n const last = points[points.length - 1];\n if (!last || last[0] !== p[0] || last[1] !== p[1]) points.push(p);\n }\n if (points.length < 2) {\n return { vertices: new Float32Array(0), vertexCount: 0 };\n }\n\n // Cumulative mercator distance -> progress 0..1 along the line.\n const cumulative: number[] = [0];\n for (let i = 1; i < points.length; i++) {\n const dx = points[i]![0] - points[i - 1]![0];\n const dy = points[i]![1] - points[i - 1]![1];\n cumulative.push(cumulative[i - 1]! + Math.hypot(dx, dy));\n }\n const total = cumulative[cumulative.length - 1]!;\n\n const vertices = new Float32Array(\n points.length * 2 * RIBBON_FLOATS_PER_VERTEX,\n );\n let out = 0;\n for (let i = 0; i < points.length; i++) {\n const prev = points[i - 1];\n const here = points[i]!;\n const next = points[i + 1];\n // Direction at this point: the segment direction at the ends, the\n // normalised average of both segment directions at interior joins.\n let dirX = 0;\n let dirY = 0;\n if (prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX += (here[0] - prev[0]) / len;\n dirY += (here[1] - prev[1]) / len;\n }\n if (next) {\n const len = Math.hypot(next[0] - here[0], next[1] - here[1]);\n dirX += (next[0] - here[0]) / len;\n dirY += (next[1] - here[1]) / len;\n }\n const dirLen = Math.hypot(dirX, dirY);\n // A perfect 180-degree switchback averages to zero; fall back to the\n // incoming segment's direction.\n if (dirLen < 1e-12 && prev) {\n const len = Math.hypot(here[0] - prev[0], here[1] - prev[1]);\n dirX = (here[0] - prev[0]) / len;\n dirY = (here[1] - prev[1]) / len;\n } else {\n dirX /= dirLen;\n dirY /= dirLen;\n }\n // Left-hand unit normal to the direction of travel.\n const nx = -dirY;\n const ny = dirX;\n const progress = total > 0 ? cumulative[i]! / total : 0;\n // Two strip vertices: one extruded each side of the centreline.\n for (const side of [1, -1]) {\n vertices[out++] = here[0];\n vertices[out++] = here[1];\n vertices[out++] = nx * side;\n vertices[out++] = ny * side;\n vertices[out++] = progress;\n }\n }\n return { vertices, vertexCount: points.length * 2 };\n}\n\n/**\n * Parse a CSS colour to premultiplication-ready `[r, g, b, a]` (0-1\n * channels). Supports the hex forms and `rgb()`/`rgba()`; anything else\n * (named colours, `hsl()`) returns `undefined` and the caller falls back\n * to the default - this runs where no canvas is guaranteed, so no\n * browser colour parser is available.\n */\nexport function parseCssColour(\n colour: string,\n): [number, number, number, number] | undefined {\n const v = colour.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n if (!/^[0-9a-fA-F]+$/.test(hex)) return undefined;\n if (hex.length === 3 || hex.length === 4) {\n const parts = hex.split(\"\").map((c) => parseInt(c + c, 16) / 255);\n const [r, g, b, a] = parts;\n if (r === undefined || g === undefined || b === undefined) return undefined;\n return [r, g, b, a ?? 1];\n }\n if (hex.length === 6 || hex.length === 8) {\n const chan = (i: number): number =>\n parseInt(hex.slice(i, i + 2), 16) / 255;\n return [chan(0), chan(2), chan(4), hex.length === 8 ? chan(6) : 1];\n }\n return undefined;\n }\n const fn = /^rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*(?:,\\s*([\\d.]+)\\s*)?\\)$/.exec(v);\n if (fn) {\n const r = Number(fn[1]) / 255;\n const g = Number(fn[2]) / 255;\n const b = Number(fn[3]) / 255;\n const a = fn[4] !== undefined ? Number(fn[4]) : 1;\n if ([r, g, b, a].some((c) => !Number.isFinite(c) || c < 0 || c > 1)) {\n return undefined;\n }\n return [r, g, b, a];\n }\n return undefined;\n}\n\n/** Whether the user has asked for reduced motion. Safe without a DOM. */\nexport function prefersReducedMotion(): boolean {\n if (typeof matchMedia !== \"function\") return false;\n try {\n return matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n}\n\nconst VERTEX_SHADER = `\nuniform mat4 u_matrix;\nuniform float u_half_width;\nattribute vec2 a_pos;\nattribute vec2 a_normal;\nattribute float a_progress;\nvarying float v_progress;\nvoid main() {\n v_progress = a_progress;\n gl_Position = u_matrix * vec4(a_pos + a_normal * u_half_width, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision mediump float;\nuniform vec4 u_color;\nuniform float u_phase;\nuniform float u_repeats;\nvarying float v_progress;\nvoid main() {\n float t = fract(v_progress * u_repeats - u_phase);\n // A soft comet: rises quickly, decays slowly, never fully dark so the\n // ribbon always traces the route.\n float pulse = smoothstep(0.0, 0.25, t) * (1.0 - smoothstep(0.35, 1.0, t));\n float energy = 0.25 + 0.75 * pulse;\n float alpha = u_color.a * energy;\n // Premultiplied alpha, matching MapLibre's framebuffer convention.\n gl_FragColor = vec4(u_color.rgb * alpha, alpha);\n}\n`;\n\n/** Warned-once flag for WebGL setup failures (one line per page, not per frame). */\nlet warnedWebglFailure = false;\n\n/** Test-only reset for the warn-once flag. */\nexport function resetEffectsWarnings(): void {\n warnedWebglFailure = false;\n}\n\n/** Default flow parameters (exported so docs/tests state one truth). */\nexport const FLOW_DEFAULTS = {\n color: FLOW_COLOUR,\n width: 10,\n speed: 0.6,\n} as const;\n\n/** World size in pixels at a zoom, for the pixel->mercator width scale. */\nfunction mercatorUnitsPerPixel(zoom: number): number {\n return 1 / (512 * 2 ** zoom);\n}\n\n/**\n * Great-circle length of a route in metres (drives how many flow pulses\n * fit along it, so short and long routes animate at a similar density).\n */\nfunction routeLengthM(coordinates: [number, number][]): number {\n let length = 0;\n for (let i = 1; i < coordinates.length; i++) {\n length += haversineM(coordinates[i - 1]!, coordinates[i]!);\n }\n return length;\n}\n\n/**\n * A MapLibre custom layer (`CustomLayerInterface`) drawing the flowing\n * route ribbon. Construct via {@link createRouteEffect} (the registry) or\n * use `MapMapMap.setRouteEffect(\"flow\")`, which manages the lifecycle.\n */\nexport class FlowRouteEffectLayer implements CustomLayerInterface {\n readonly id: string;\n readonly type = \"custom\" as const;\n readonly renderingMode = \"2d\" as const;\n\n private geometry: RouteGeometry;\n private readonly colour: [number, number, number, number];\n private readonly widthPx: number;\n private readonly speed: number;\n private readonly animate: boolean;\n\n private mapRef: MlMap | undefined;\n private glRef: WebGLRenderingContext | WebGL2RenderingContext | undefined;\n private program: WebGLProgram | null = null;\n private buffer: WebGLBuffer | null = null;\n private vertexCount = 0;\n private repeats = 8;\n private startedAt = 0;\n private failed = false;\n private aPos = 0;\n private aNormal = 0;\n private aProgress = 0;\n private uMatrix: WebGLUniformLocation | null = null;\n private uHalfWidth: WebGLUniformLocation | null = null;\n private uColor: WebGLUniformLocation | null = null;\n private uPhase: WebGLUniformLocation | null = null;\n private uRepeats: WebGLUniformLocation | null = null;\n\n constructor(geometry: RouteGeometry, options: RouteFlowOptions = {}) {\n this.id = options.id ?? \"mapmap-route-effect\";\n this.geometry = geometry;\n this.colour =\n (options.color !== undefined ? parseCssColour(options.color) : undefined) ??\n (parseCssColour(FLOW_DEFAULTS.color) as [number, number, number, number]);\n this.widthPx = options.width ?? FLOW_DEFAULTS.width;\n this.speed = options.speed ?? FLOW_DEFAULTS.speed;\n // Reduced motion: keep the ribbon (a static gradient still marks the\n // route) but freeze the phase and never request repaints.\n this.animate = !prefersReducedMotion();\n }\n\n /** Swap the ribbon onto a new route line (e.g. after a reroute). */\n setGeometry(geometry: RouteGeometry): void {\n this.geometry = geometry;\n if (this.glRef && !this.failed) this.upload(this.glRef);\n this.mapRef?.triggerRepaint();\n }\n\n onAdd(map: MlMap, gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n this.mapRef = map;\n this.glRef = gl;\n this.startedAt = now();\n try {\n const program = gl.createProgram();\n if (!program) throw new Error(\"createProgram returned null\");\n for (const [kind, source] of [\n [gl.VERTEX_SHADER, VERTEX_SHADER],\n [gl.FRAGMENT_SHADER, FRAGMENT_SHADER],\n ] as const) {\n const shader = gl.createShader(kind);\n if (!shader) throw new Error(\"createShader returned null\");\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(gl.getShaderInfoLog(shader) ?? \"shader compile failed\");\n }\n gl.attachShader(program, shader);\n }\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(gl.getProgramInfoLog(program) ?? \"program link failed\");\n }\n this.program = program;\n this.aPos = gl.getAttribLocation(program, \"a_pos\");\n this.aNormal = gl.getAttribLocation(program, \"a_normal\");\n this.aProgress = gl.getAttribLocation(program, \"a_progress\");\n this.uMatrix = gl.getUniformLocation(program, \"u_matrix\");\n this.uHalfWidth = gl.getUniformLocation(program, \"u_half_width\");\n this.uColor = gl.getUniformLocation(program, \"u_color\");\n this.uPhase = gl.getUniformLocation(program, \"u_phase\");\n this.uRepeats = gl.getUniformLocation(program, \"u_repeats\");\n this.upload(gl);\n } catch (error) {\n // Static fallback: the plain route line underneath is untouched;\n // the ribbon simply never draws. One warning per page.\n this.failed = true;\n if (!warnedWebglFailure) {\n warnedWebglFailure = true;\n console.warn(\n `MapMap: route effect \"flow\" disabled (WebGL setup failed: ` +\n `${error instanceof Error ? error.message : String(error)}). ` +\n \"Falling back to the plain route line.\",\n );\n }\n }\n }\n\n onRemove(\n _map: MlMap,\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n ): void {\n if (this.buffer) gl.deleteBuffer(this.buffer);\n if (this.program) gl.deleteProgram(this.program);\n this.buffer = null;\n this.program = null;\n this.mapRef = undefined;\n this.glRef = undefined;\n }\n\n render(gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void {\n if (this.failed || !this.program || !this.buffer || this.vertexCount < 3) {\n return;\n }\n const matrix = projectionMatrixOf(args);\n if (!matrix || !this.mapRef) return;\n\n gl.useProgram(this.program);\n gl.uniformMatrix4fv(this.uMatrix, false, matrix);\n const halfWidth =\n (this.widthPx / 2) * mercatorUnitsPerPixel(this.mapRef.getZoom());\n gl.uniform1f(this.uHalfWidth, halfWidth);\n gl.uniform4f(this.uColor, ...this.colour);\n const phase = this.animate\n ? ((now() - this.startedAt) / 1000) * this.speed % 1\n : 0;\n gl.uniform1f(this.uPhase, phase);\n gl.uniform1f(this.uRepeats, this.repeats);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n const stride = RIBBON_FLOATS_PER_VERTEX * 4;\n gl.enableVertexAttribArray(this.aPos);\n gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);\n gl.enableVertexAttribArray(this.aNormal);\n gl.vertexAttribPointer(this.aNormal, 2, gl.FLOAT, false, stride, 8);\n gl.enableVertexAttribArray(this.aProgress);\n gl.vertexAttribPointer(this.aProgress, 1, gl.FLOAT, false, stride, 16);\n\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); // premultiplied alpha\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.vertexCount);\n\n if (this.animate) this.mapRef.triggerRepaint();\n }\n\n private upload(gl: WebGLRenderingContext | WebGL2RenderingContext): void {\n const mesh = tessellateRouteRibbon(this.geometry.coordinates);\n this.vertexCount = mesh.vertexCount;\n // Pulse density scales with route length: one pulse roughly every\n // 500 m, clamped so a short hop still flows and a long haul doesn't\n // strobe.\n this.repeats = Math.min(\n 80,\n Math.max(2, Math.round(routeLengthM(this.geometry.coordinates) / 500)),\n );\n if (!this.buffer) this.buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n gl.bufferData(gl.ARRAY_BUFFER, mesh.vertices, gl.STATIC_DRAW);\n }\n}\n\n/** Monotonic-ish clock that works in browsers and Node tests. */\nfunction now(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\n/**\n * The main projection matrix out of a custom layer `render` argument:\n * MapLibre v4 passes the matrix itself, v5 passes an args object carrying\n * `defaultProjectionData.mainMatrix`.\n */\nfunction projectionMatrixOf(args: unknown): Float32Array | number[] | undefined {\n if (Array.isArray(args)) return args as number[];\n if (args instanceof Float32Array || args instanceof Float64Array) {\n return args instanceof Float64Array ? new Float32Array(args) : args;\n }\n if (typeof args === \"object\" && args !== null) {\n const data = (args as { defaultProjectionData?: { mainMatrix?: unknown } })\n .defaultProjectionData;\n const main = data?.mainMatrix;\n if (Array.isArray(main)) return main as number[];\n if (main instanceof Float32Array) return main;\n if (main instanceof Float64Array) return new Float32Array(main);\n }\n return undefined;\n}\n\n/** A route effect layer: a custom layer that can retarget its geometry. */\nexport interface RouteEffectLayer extends CustomLayerInterface {\n setGeometry(geometry: RouteGeometry): void;\n}\n\n/**\n * The effect registry: name -> layer factory. New effects (ambient life,\n * seasonal snow, fog-of-exploration) add an entry here and a name to\n * {@link RouteEffectName}.\n */\nexport const ROUTE_EFFECTS: Record<\n RouteEffectName,\n (geometry: RouteGeometry, options?: RouteFlowOptions) => RouteEffectLayer\n> = {\n flow: (geometry, options) => new FlowRouteEffectLayer(geometry, options),\n};\n\n/**\n * Create a named route effect layer. Throws an agent-readable error for\n * unknown names (the accepted list included).\n */\nexport function createRouteEffect(\n name: RouteEffectName,\n geometry: RouteGeometry,\n options?: RouteFlowOptions,\n): RouteEffectLayer {\n const factory = ROUTE_EFFECTS[name];\n if (!factory) {\n throw new Error(\n `unknown route effect ${JSON.stringify(name)}; accepted effects: ` +\n Object.keys(ROUTE_EFFECTS).join(\", \"),\n );\n }\n return factory(geometry, options);\n}\n","/**\n * The MapMap logo control: a small wordmark on the map, the same\n * convention as Google Maps' and Mapbox's marks. On by default in\n * {@link MapMapMap}; positionable, and removable with `logo: false`\n * (attribution itself is separate and never removable).\n *\n * The mark is an inline SVG (no network fetch, works offline and under\n * strict CSPs): the MapMap brand lockup — the three-colour route mark\n * plus the lowercase wordmark. Height stays at 20px so existing layouts\n * hold.\n */\n\n/** Corner positions accepted by the logo control. */\nexport type LogoPosition = \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n\n/** Options for {@link LogoControl}. */\nexport interface LogoOptions {\n /** Corner to render in. Default `bottom-right`, above the attribution. */\n position?: LogoPosition;\n /** Link target when clicked. Default the MapMap site. */\n href?: string;\n}\n\n/**\n * The inline wordmark (height 20px): the outline-light lockup — the\n * line-art route mark plus the dark wordmark — over a white halo stroke\n * so it stays legible on any base map.\n */\nexport const LOGO_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"84\" height=\"20\" viewBox=\"0 0 156 37\" fill=\"none\" role=\"img\" aria-label=\"MapMap\">' +\n '<g stroke=\"#ffffff\" stroke-linejoin=\"round\" stroke-linecap=\"round\">' +\n '<path d=\"M146.965 19.2363C146.965 17.5281 146.64 16.2469 145.989 15.3927C145.358 14.5386 144.464 14.1115 143.304 14.1115C142.227 14.1115 141.352 14.5589 140.681 15.4537C140.03 16.3282 139.705 17.5382 139.705 19.0838V19.3889C139.705 20.9751 140.03 22.2055 140.681 23.08C141.352 23.9341 142.227 24.3612 143.304 24.3612C144.382 24.3612 145.257 23.924 145.928 23.0495C146.619 22.1547 146.965 20.8836 146.965 19.2363ZM150.778 19.2363C150.778 21.8598 150.188 23.8934 149.009 25.3373C147.85 26.7609 146.324 27.4727 144.433 27.4727C142.481 27.4727 140.925 26.7304 139.766 25.2458H139.705V33.8787H135.739V11.305H139.461L139.522 13.5319H139.583C140.803 11.844 142.42 11 144.433 11C146.406 11 147.951 11.7016 149.07 13.1048C150.209 14.5081 150.778 16.5519 150.778 19.2363Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M126.399 11C128.819 11 130.558 11.4779 131.615 12.4337C132.673 13.3692 133.202 14.8945 133.202 17.0095V22.8969C133.202 24.3409 133.354 25.7644 133.659 27.1676H129.907C129.785 26.4965 129.694 25.7136 129.633 24.8188H129.572C129.002 25.6526 128.229 26.3033 127.253 26.7711C126.297 27.2388 125.25 27.4727 124.111 27.4727C122.627 27.4727 121.437 27.066 120.542 26.2525C119.668 25.4187 119.23 24.2697 119.23 22.8054C119.23 21.0361 119.973 19.6227 121.457 18.5652C122.962 17.4874 125.118 16.9485 127.924 16.9485H129.236V16.857C129.236 15.7791 129.023 15.0267 128.596 14.5996C128.168 14.1725 127.406 13.959 126.308 13.959C124.315 13.959 122.433 14.4166 120.664 15.3317L120.085 12.3727C122.017 11.4576 124.121 11 126.399 11ZM122.952 22.5004C122.952 23.1512 123.145 23.6596 123.532 24.0256C123.918 24.3917 124.447 24.5747 125.118 24.5747C126.277 24.5747 127.253 24.1985 128.046 23.446C128.84 22.6936 129.236 21.7479 129.236 20.6091V19.5719H127.924C126.318 19.5719 125.087 19.8464 124.233 20.3955C123.379 20.9243 122.952 21.6259 122.952 22.5004Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M96.1152 11.305H99.7758L99.8673 13.4404H99.9284C101.108 11.8135 102.46 11 103.986 11C104.982 11 105.806 11.2034 106.456 11.6101C107.107 12.0168 107.666 12.6778 108.134 13.5929H108.195C109.517 11.8643 111.073 11 112.862 11C114.571 11 115.811 11.4779 116.584 12.4337C117.377 13.3692 117.774 14.9555 117.774 17.1925V27.1676H113.93V18.1077C113.93 16.5214 113.757 15.4537 113.412 14.9046C113.086 14.3555 112.496 14.081 111.642 14.081C110.91 14.081 110.27 14.4674 109.72 15.2402C109.171 16.013 108.897 16.9688 108.897 18.1077V27.1676H105.053V18.1077C105.053 16.5214 104.88 15.4537 104.535 14.9046C104.209 14.3555 103.619 14.081 102.765 14.081C102.033 14.081 101.393 14.4674 100.844 15.2402C100.294 16.013 100.02 16.9688 100.02 18.1077V27.1676H96.1152V11.305Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M90.8503 19.2363C90.8503 17.5281 90.525 16.2469 89.8742 15.3927C89.2438 14.5386 88.3489 14.1115 87.1898 14.1115C86.1119 14.1115 85.2374 14.5589 84.5663 15.4537C83.9155 16.3282 83.5902 17.5382 83.5902 19.0838V19.3889C83.5902 20.9751 83.9155 22.2055 84.5663 23.08C85.2374 23.9341 86.1119 24.3612 87.1898 24.3612C88.2676 24.3612 89.1421 23.924 89.8132 23.0495C90.5046 22.1547 90.8503 20.8836 90.8503 19.2363ZM94.6635 19.2363C94.6635 21.8598 94.0737 23.8934 92.8942 25.3373C91.735 26.7609 90.2097 27.4727 88.3184 27.4727C86.3661 27.4727 84.8104 26.7304 83.6512 25.2458H83.5902V33.8787H79.6245V11.305H83.3461L83.4071 13.5319H83.4681C84.6883 11.844 86.3051 11 88.3184 11C90.2911 11 91.8367 11.7016 92.9552 13.1048C94.094 14.5081 94.6635 16.5519 94.6635 19.2363Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M70.2844 11C72.7045 11 74.4432 11.4779 75.5008 12.4337C76.5583 13.3692 77.087 14.8945 77.087 17.0095V22.8969C77.087 24.3409 77.2395 25.7644 77.5446 27.1676H73.7925C73.6705 26.4965 73.5789 25.7136 73.5179 24.8188H73.4569C72.8875 25.6526 72.1147 26.3033 71.1385 26.7711C70.1827 27.2388 69.1354 27.4727 67.9965 27.4727C66.5119 27.4727 65.3223 27.066 64.4274 26.2525C63.553 25.4187 63.1157 24.2697 63.1157 22.8054C63.1157 21.0361 63.858 19.6227 65.3426 18.5652C66.8475 17.4874 69.0032 16.9485 71.8096 16.9485H73.1214V16.857C73.1214 15.7791 72.9078 15.0267 72.4808 14.5996C72.0537 14.1725 71.2911 13.959 70.1929 13.959C68.1999 13.959 66.3187 14.4166 64.5495 15.3317L63.9699 12.3727C65.9018 11.4576 68.0067 11 70.2844 11ZM66.8373 22.5004C66.8373 23.1512 67.0305 23.6596 67.4169 24.0256C67.8033 24.3917 68.3321 24.5747 69.0032 24.5747C70.1624 24.5747 71.1385 24.1985 71.9317 23.446C72.7248 22.6936 73.1214 21.7479 73.1214 20.6091V19.5719H71.8096C70.203 19.5719 68.9727 19.8464 68.1185 20.3955C67.2644 20.9243 66.8373 21.6259 66.8373 22.5004Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M40 11.3049H43.6606L43.7521 13.4403H43.8131C44.9927 11.8133 46.345 10.9999 47.8703 10.9999C48.8668 10.9999 49.6904 11.2032 50.3412 11.61C50.992 12.0167 51.5512 12.6777 52.019 13.5928H52.08C53.4019 11.8642 54.9576 10.9999 56.7472 10.9999C58.4555 10.9999 59.6961 11.4778 60.4689 12.4336C61.262 13.3691 61.6586 14.9554 61.6586 17.1924V27.1675H57.8149V18.1075C57.8149 16.5213 57.6421 15.4536 57.2963 14.9045C56.9709 14.3554 56.3812 14.0809 55.527 14.0809C54.7949 14.0809 54.1543 14.4673 53.6052 15.2401C53.0561 16.0129 52.7816 16.9687 52.7816 18.1075V27.1675H48.938V18.1075C48.938 16.5213 48.7651 15.4536 48.4194 14.9045C48.094 14.3554 47.5042 14.0809 46.6501 14.0809C45.918 14.0809 45.2774 14.4673 44.7283 15.2401C44.1792 16.0129 43.9046 16.9687 43.9046 18.1075V27.1675H40V11.3049Z\" fill=\"#ffffff\" stroke-width=\"3\" paint-order=\"stroke\"/>' +\n '<path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke-width=\"4.96\"/>' +\n '<path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke-width=\"4.96\"/>' +\n '<path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke-width=\"4.96\"/>' +\n '</g>' +\n '<path d=\"M146.965 19.2363C146.965 17.5281 146.64 16.2469 145.989 15.3927C145.358 14.5386 144.464 14.1115 143.304 14.1115C142.227 14.1115 141.352 14.5589 140.681 15.4537C140.03 16.3282 139.705 17.5382 139.705 19.0838V19.3889C139.705 20.9751 140.03 22.2055 140.681 23.08C141.352 23.9341 142.227 24.3612 143.304 24.3612C144.382 24.3612 145.257 23.924 145.928 23.0495C146.619 22.1547 146.965 20.8836 146.965 19.2363ZM150.778 19.2363C150.778 21.8598 150.188 23.8934 149.009 25.3373C147.85 26.7609 146.324 27.4727 144.433 27.4727C142.481 27.4727 140.925 26.7304 139.766 25.2458H139.705V33.8787H135.739V11.305H139.461L139.522 13.5319H139.583C140.803 11.844 142.42 11 144.433 11C146.406 11 147.951 11.7016 149.07 13.1048C150.209 14.5081 150.778 16.5519 150.778 19.2363Z\" fill=\"#26282A\"/>' +\n '<path d=\"M126.399 11C128.819 11 130.558 11.4779 131.615 12.4337C132.673 13.3692 133.202 14.8945 133.202 17.0095V22.8969C133.202 24.3409 133.354 25.7644 133.659 27.1676H129.907C129.785 26.4965 129.694 25.7136 129.633 24.8188H129.572C129.002 25.6526 128.229 26.3033 127.253 26.7711C126.297 27.2388 125.25 27.4727 124.111 27.4727C122.627 27.4727 121.437 27.066 120.542 26.2525C119.668 25.4187 119.23 24.2697 119.23 22.8054C119.23 21.0361 119.973 19.6227 121.457 18.5652C122.962 17.4874 125.118 16.9485 127.924 16.9485H129.236V16.857C129.236 15.7791 129.023 15.0267 128.596 14.5996C128.168 14.1725 127.406 13.959 126.308 13.959C124.315 13.959 122.433 14.4166 120.664 15.3317L120.085 12.3727C122.017 11.4576 124.121 11 126.399 11ZM122.952 22.5004C122.952 23.1512 123.145 23.6596 123.532 24.0256C123.918 24.3917 124.447 24.5747 125.118 24.5747C126.277 24.5747 127.253 24.1985 128.046 23.446C128.84 22.6936 129.236 21.7479 129.236 20.6091V19.5719H127.924C126.318 19.5719 125.087 19.8464 124.233 20.3955C123.379 20.9243 122.952 21.6259 122.952 22.5004Z\" fill=\"#26282A\"/>' +\n '<path d=\"M96.1152 11.305H99.7758L99.8673 13.4404H99.9284C101.108 11.8135 102.46 11 103.986 11C104.982 11 105.806 11.2034 106.456 11.6101C107.107 12.0168 107.666 12.6778 108.134 13.5929H108.195C109.517 11.8643 111.073 11 112.862 11C114.571 11 115.811 11.4779 116.584 12.4337C117.377 13.3692 117.774 14.9555 117.774 17.1925V27.1676H113.93V18.1077C113.93 16.5214 113.757 15.4537 113.412 14.9046C113.086 14.3555 112.496 14.081 111.642 14.081C110.91 14.081 110.27 14.4674 109.72 15.2402C109.171 16.013 108.897 16.9688 108.897 18.1077V27.1676H105.053V18.1077C105.053 16.5214 104.88 15.4537 104.535 14.9046C104.209 14.3555 103.619 14.081 102.765 14.081C102.033 14.081 101.393 14.4674 100.844 15.2402C100.294 16.013 100.02 16.9688 100.02 18.1077V27.1676H96.1152V11.305Z\" fill=\"#26282A\"/>' +\n '<path d=\"M90.8503 19.2363C90.8503 17.5281 90.525 16.2469 89.8742 15.3927C89.2438 14.5386 88.3489 14.1115 87.1898 14.1115C86.1119 14.1115 85.2374 14.5589 84.5663 15.4537C83.9155 16.3282 83.5902 17.5382 83.5902 19.0838V19.3889C83.5902 20.9751 83.9155 22.2055 84.5663 23.08C85.2374 23.9341 86.1119 24.3612 87.1898 24.3612C88.2676 24.3612 89.1421 23.924 89.8132 23.0495C90.5046 22.1547 90.8503 20.8836 90.8503 19.2363ZM94.6635 19.2363C94.6635 21.8598 94.0737 23.8934 92.8942 25.3373C91.735 26.7609 90.2097 27.4727 88.3184 27.4727C86.3661 27.4727 84.8104 26.7304 83.6512 25.2458H83.5902V33.8787H79.6245V11.305H83.3461L83.4071 13.5319H83.4681C84.6883 11.844 86.3051 11 88.3184 11C90.2911 11 91.8367 11.7016 92.9552 13.1048C94.094 14.5081 94.6635 16.5519 94.6635 19.2363Z\" fill=\"#26282A\"/>' +\n '<path d=\"M70.2844 11C72.7045 11 74.4432 11.4779 75.5008 12.4337C76.5583 13.3692 77.087 14.8945 77.087 17.0095V22.8969C77.087 24.3409 77.2395 25.7644 77.5446 27.1676H73.7925C73.6705 26.4965 73.5789 25.7136 73.5179 24.8188H73.4569C72.8875 25.6526 72.1147 26.3033 71.1385 26.7711C70.1827 27.2388 69.1354 27.4727 67.9965 27.4727C66.5119 27.4727 65.3223 27.066 64.4274 26.2525C63.553 25.4187 63.1157 24.2697 63.1157 22.8054C63.1157 21.0361 63.858 19.6227 65.3426 18.5652C66.8475 17.4874 69.0032 16.9485 71.8096 16.9485H73.1214V16.857C73.1214 15.7791 72.9078 15.0267 72.4808 14.5996C72.0537 14.1725 71.2911 13.959 70.1929 13.959C68.1999 13.959 66.3187 14.4166 64.5495 15.3317L63.9699 12.3727C65.9018 11.4576 68.0067 11 70.2844 11ZM66.8373 22.5004C66.8373 23.1512 67.0305 23.6596 67.4169 24.0256C67.8033 24.3917 68.3321 24.5747 69.0032 24.5747C70.1624 24.5747 71.1385 24.1985 71.9317 23.446C72.7248 22.6936 73.1214 21.7479 73.1214 20.6091V19.5719H71.8096C70.203 19.5719 68.9727 19.8464 68.1185 20.3955C67.2644 20.9243 66.8373 21.6259 66.8373 22.5004Z\" fill=\"#26282A\"/>' +\n '<path d=\"M40 11.3049H43.6606L43.7521 13.4403H43.8131C44.9927 11.8133 46.345 10.9999 47.8703 10.9999C48.8668 10.9999 49.6904 11.2032 50.3412 11.61C50.992 12.0167 51.5512 12.6777 52.019 13.5928H52.08C53.4019 11.8642 54.9576 10.9999 56.7472 10.9999C58.4555 10.9999 59.6961 11.4778 60.4689 12.4336C61.262 13.3691 61.6586 14.9554 61.6586 17.1924V27.1675H57.8149V18.1075C57.8149 16.5213 57.6421 15.4536 57.2963 14.9045C56.9709 14.3554 56.3812 14.0809 55.527 14.0809C54.7949 14.0809 54.1543 14.4673 53.6052 15.2401C53.0561 16.0129 52.7816 16.9687 52.7816 18.1075V27.1675H48.938V18.1075C48.938 16.5213 48.7651 15.4536 48.4194 14.9045C48.094 14.3554 47.5042 14.0809 46.6501 14.0809C45.918 14.0809 45.2774 14.4673 44.7283 15.2401C44.1792 16.0129 43.9046 16.9687 43.9046 18.1075V27.1675H40V11.3049Z\" fill=\"#26282A\"/>' +\n '<path d=\"M27.3847 25.9178C28.8081 23.5868 30.5287 21.3029 30.9562 18.5589C31.9911 11.9172 26.9381 5.71447 19.956 5.30338C17.4904 5.15838 13.6449 5.12507 11.1992 5.30299C10.0552 5.38607 8.94122 5.89121 8.16887 6.70868C7.71694 7.18718 5.28183 11.1346 5.20651 11.6441C5.02777 12.8495 5.83228 13.8426 7.09035 13.9645C9.18143 14.1667 11.8763 13.9253 14.0309 13.9264C15.8964 13.9272 17.9989 13.8097 19.8339 13.9253C25.9341 14.3093 29.7128 20.5446 27.3249 25.9319L27.3847 25.9178Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '<path d=\"M14.0302 13.9258L10.6029 19.6599C9.96327 20.8096 10.6737 22.3059 12.0613 22.4638C14.1002 22.6962 17.0133 22.4493 19.1606 22.4689C21.213 22.4877 23.197 22.146 24.8203 23.6246C26.1443 24.8308 26.5555 26.7091 25.9192 28.3472L27.3849 25.9175C29.7728 20.5302 25.9338 14.3083 19.8336 13.9246C17.9986 13.809 15.8961 13.927 14.0306 13.9258H14.0302Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '<path d=\"M19.1603 22.469L15.6471 28.3947C15.2098 29.3278 15.7183 30.5509 16.7183 30.9134C17.4381 31.174 21.8747 31.1148 22.7354 30.9463C24.1038 30.6786 25.4299 29.6056 25.9188 28.3477C26.5548 26.7096 26.1436 24.8313 24.82 23.6251C23.1967 22.1461 21.1733 22.5542 19.1209 22.5354L19.1603 22.469Z\" stroke=\"#3A3838\" stroke-width=\"1.95943\" stroke-miterlimit=\"10\"/>' +\n '</svg>';\n\nconst DEFAULT_HREF = \"https://mapmap.ai\";\n\n/**\n * A MapLibre `IControl` rendering the MapMap wordmark. Typed structurally\n * (`onAdd`/`onRemove`) so it needs no maplibre-gl import and works with\n * any instance the host app bundles.\n */\nexport class LogoControl {\n private container: HTMLElement | undefined;\n private readonly href: string;\n\n constructor(options: LogoOptions = {}) {\n this.href = options.href ?? DEFAULT_HREF;\n }\n\n onAdd(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"LogoControl requires a DOM environment\");\n const link = doc.createElement(\"a\");\n link.className = \"maplibregl-ctrl mapmap-logo\";\n link.href = this.href;\n link.target = \"_blank\";\n link.rel = \"noopener\";\n link.setAttribute(\"aria-label\", \"MapMap\");\n link.style.cssText =\n \"display:block;line-height:0;margin:0 8px 4px 8px;opacity:0.9;pointer-events:auto\";\n // LOGO_SVG is a compile-time constant, parsed rather than assigned to\n // innerHTML so no HTML-injection surface exists even if it changes.\n const svg = new DOMParser().parseFromString(LOGO_SVG, \"image/svg+xml\").documentElement;\n link.appendChild(doc.importNode(svg, true));\n this.container = link;\n return link;\n }\n\n onRemove(): void {\n this.container?.remove();\n this.container = undefined;\n }\n}\n","/**\n * Studio navigation-design block (`extra.nav`) - types, defaults and parser.\n *\n * MapMap Studio's Navigation panel designs the turn-by-turn look - route\n * line, current-position puck and banner instruction - and stores the result\n * as a small design-token block under `extra.nav` in the theme JSON it\n * downloads/copies. This module reads that block so the same theme file\n * styles real navigation UI: `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` all accept a design from it.\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-nav.ts` (the Studio\n * reference parser) - identical interfaces, defaults, clamps and URL rules.\n * Keep the two in sync so a theme previews in Studio exactly as the SDK\n * renders it. Not imported from the website because the packages do not\n * depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. That includes hosted publishing: the canonical\n * `sn_style` crate stores `extra` verbatim (bounded at 256 KB serialised)\n * and the gateway serves it back from `GET /styles/{id}/theme`, so a design\n * survives Studio's publish flow too. Read it from a theme file you pass to\n * `createMap` / `buildStyle`, or fetch it from a hosted style with\n * {@link navDesignFromThemeUrl} — a compiled style URL alone never carries\n * it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** Route-line tokens (defaults match {@link RouteLayer}'s built-in look). */\nexport interface NavRouteDesign {\n /** Line colour. Default is MapMap signal blue (`SIGNAL_BLUE`). */\n color: string;\n /** Line width in px at mid zoom. */\n width: number;\n /** Line opacity, 0-1. */\n opacity: number;\n /** Casing (outline) colour drawn under the line. */\n casingColor: string;\n}\n\n/** Current-position puck tokens. */\nexport interface NavPuckDesign {\n /** Puck fill colour. */\n color: string;\n /** Puck diameter in px. */\n size: number;\n /** Whether the heading arrow is drawn on the puck. */\n headingArrow: boolean;\n /**\n * Optional custom puck image (`https:` or `data:` URI, PNG/SVG). When set\n * it replaces the built-in dot + arrow; `size` still scales it. Optional\n * since v1 - themes saved without it load unchanged.\n */\n imageUrl?: string;\n}\n\n/** Banner-instruction tokens (defaults match {@link GuidanceBanner}). */\nexport interface NavBannerDesign {\n /** Banner background colour. */\n background: string;\n /** Banner text (and arrow) colour. */\n textColor: string;\n /** Primary text size in px. */\n fontSize: number;\n /** Whether the lane diagram row is shown when lanes are present. */\n showLanes: boolean;\n /** Inner padding in px, 6-24. Optional since v1; default 10. */\n padding?: number;\n /** Corner radius in px, 0-24. Optional since v1; default 10. */\n cornerRadius?: number;\n /** Maximum banner width in px, 200-520. Optional since v1; default 340. */\n maxWidth?: number;\n /**\n * Banner height in px, 40-120. Optional since v1; unset means auto -\n * the banner takes its natural content height (old themes keep theirs).\n */\n height?: number;\n}\n\n/**\n * Drive-camera tokens: how the chase cam frames a turn-by-turn drive.\n * The whole block is optional since v1 - themes saved without it load\n * unchanged and the SDK keeps its built-in framing. Every field is itself\n * optional (absent = the documented default). `NavigationCamera` reads\n * `pitch`/`zoom` as its option defaults; `speedMps` drives Studio's demo\n * drive (and any route simulator) - a camera following real GPS fixes\n * ignores it.\n */\nexport interface NavCameraDesign {\n /** Chase-cam tilt in degrees, 0-85. Default 60. */\n pitch?: number;\n /** Chase-cam zoom, 14-20. Default 17.5. */\n zoom?: number;\n /** Drive speed in metres per second, 2-40. Default 12 (~43 km/h). */\n speedMps?: number;\n}\n\n/**\n * Defaults for the optional `camera` block. LOCKSTEP: mirrors\n * `NAV_CAMERA_DEFAULTS` in `website/lib/studio-nav.ts`.\n */\nexport const NAV_CAMERA_DEFAULTS = {\n pitch: 60,\n zoom: 17.5,\n speedMps: 12,\n} as const;\n\n/** The `extra.nav` block: navigation design tokens for the SDKs. */\nexport interface NavDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n route: NavRouteDesign;\n puck: NavPuckDesign;\n banner: NavBannerDesign;\n /**\n * Optional since v1: drive-camera framing (pitch/zoom) and speed. Absent\n * means \"SDK built-ins\" - the block stays `version: 1` either way.\n */\n camera?: NavCameraDesign;\n}\n\n/**\n * Defaults mirror what the SDK draws today with no design: `RouteLayer`'s\n * signal-blue line over a dark casing, and `GuidanceBanner`'s dark pill.\n */\nexport function defaultNavDesign(): NavDesign {\n return {\n version: 1,\n route: { color: \"#3a86ff\", width: 4.5, opacity: 1, casingColor: \"#1f438a\" },\n puck: { color: \"#1f6fff\", size: 14, headingArrow: true },\n banner: {\n background: \"#101418\",\n textColor: \"#ffffff\",\n fontSize: 16,\n showLanes: true,\n padding: 10,\n cornerRadius: 10,\n maxWidth: 340,\n },\n };\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction str(v: unknown, fallback: string): string {\n return typeof v === \"string\" && v.trim() !== \"\" ? v : fallback;\n}\n\nfunction num(v: unknown, fallback: number, min: number, max: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : fallback;\n}\n\n/** Optional clamped number: absent/malformed stays `undefined` (= auto). */\nfunction optNum(v: unknown, min: number, max: number): number | undefined {\n return typeof v === \"number\" && Number.isFinite(v) ? Math.min(max, Math.max(min, v)) : undefined;\n}\n\nfunction bool(v: unknown, fallback: boolean): boolean {\n return typeof v === \"boolean\" ? v : fallback;\n}\n\n/**\n * Optional puck-image URL: only `https:` or `data:` URIs are accepted;\n * anything else (including absence) yields `undefined` - the built-in puck.\n */\nfunction puckImageUrl(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return /^(https:|data:)/i.test(t) ? t : undefined;\n}\n\n/**\n * Lenient parse of an `extra.nav` value: unknown or malformed fields fall\n * back to the defaults, so an imported theme never fails on its nav block.\n * LOCKSTEP: identical semantics to `parseNavDesign` in\n * `website/lib/studio-nav.ts` (same clamps, same fallbacks).\n */\nexport function parseNavDesign(value: unknown): NavDesign {\n const d = defaultNavDesign();\n if (!isRecord(value)) return d;\n const route = isRecord(value.route) ? value.route : {};\n const puck = isRecord(value.puck) ? value.puck : {};\n const banner = isRecord(value.banner) ? value.banner : {};\n return {\n version: 1,\n route: {\n color: str(route.color, d.route.color),\n width: num(route.width, d.route.width, 0.5, 20),\n opacity: num(route.opacity, d.route.opacity, 0, 1),\n casingColor: str(route.casingColor, d.route.casingColor),\n },\n puck: {\n color: str(puck.color, d.puck.color),\n size: num(puck.size, d.puck.size, 6, 40),\n headingArrow: bool(puck.headingArrow, d.puck.headingArrow),\n imageUrl: puckImageUrl(puck.imageUrl),\n },\n banner: {\n background: str(banner.background, d.banner.background),\n textColor: str(banner.textColor, d.banner.textColor),\n fontSize: num(banner.fontSize, d.banner.fontSize, 10, 32),\n showLanes: bool(banner.showLanes, d.banner.showLanes),\n padding: num(banner.padding, d.banner.padding ?? 10, 6, 24),\n cornerRadius: num(banner.cornerRadius, d.banner.cornerRadius ?? 10, 0, 24),\n maxWidth: num(banner.maxWidth, d.banner.maxWidth ?? 340, 200, 520),\n height: optNum(banner.height, 40, 120),\n },\n // Camera is optional since v1: absent (or malformed) stays undefined so\n // old themes round-trip byte-identical; a present block clamps per\n // field, each absent field meaning \"use the default\".\n ...(isRecord(value.camera)\n ? {\n camera: {\n pitch: optNum(value.camera.pitch, 0, 85),\n zoom: optNum(value.camera.zoom, 14, 20),\n speedMps: optNum(value.camera.speedMps, 2, 40),\n },\n }\n : {}),\n };\n}\n\n/**\n * Reads and parses the `extra.nav` block from a Studio theme document.\n * Returns `undefined` when the theme carries no nav block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults.\n */\nexport function navDesignFromTheme(theme: Theme | undefined | null): NavDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"nav\" in extra)) {\n return undefined;\n }\n return parseNavDesign((extra as { nav?: unknown }).nav);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.nav` block.\n *\n * Point it at the gateway's theme endpoint - the design a Studio publish\n * stores alongside the compiled style:\n *\n * ```ts\n * const design = await navDesignFromThemeUrl(\n * \"https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme\",\n * );\n * ```\n *\n * The endpoint is public (no API key) and never cached, so this always\n * reflects the latest published version. Returns `undefined` when the\n * theme carries no nav block (same contract as {@link navDesignFromTheme});\n * throws on network failure, a non-2xx response or a non-JSON body.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n * Defaults to the global `fetch`.\n */\nexport async function navDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<NavDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return navDesignFromTheme(theme);\n}\n","/**\n * Studio POI category-design block (`extra.poi`) - types, defaults, parser\n * and appliers.\n *\n * MapMap Studio's POIs panel colours the ~8 POI categories - the coloured\n * category dot drawn under a POI label, and the `poi-labels` text colour -\n * and stores the result as a small design-token block under `extra.poi` in\n * the theme JSON it downloads/copies/publishes, exactly like the navigation\n * design under `extra.nav` (see nav-design.ts). This module reads that\n * block and applies the label-text part to a live MapLibre map; the dot\n * images themselves are runtime-rasterised by their host (the MapMap\n * website today - sprite-based icons arrive with marker packs).\n *\n * LOCKSTEP: this file mirrors `website/lib/studio-poi.ts` (the Studio\n * reference parser) - identical category ids, built-in colours, leniency\n * and expression building. The class->category mapping mirrors\n * `website/lib/poi-icons.ts` (`POI_CLASS_CATEGORIES`). Keep them in sync so\n * a theme previews in Studio exactly as the SDK applies it. Not imported\n * from the website because the packages do not depend on each other.\n *\n * PUBLISH NOTE: the block travels with the THEME DOCUMENT, never with the\n * compiled `style.json`. The canonical `sn_style` crate stores `extra`\n * verbatim (bounded at 256 KB serialised) and the gateway serves it back\n * from `GET /styles/{id}/theme`, so a design survives Studio's publish\n * flow. Read it from a theme file you pass to `createMap` / `buildStyle`,\n * or fetch it from a hosted style with {@link poiDesignFromThemeUrl} - a\n * compiled style URL alone never carries it.\n */\nimport type { Theme } from \"./style.js\";\n\n/** One category's overrides. Both fields optional: absent = built-in. */\nexport interface PoiCategoryDesign {\n /** Dot fill colour (replaces the built-in category brand colour). */\n color?: string;\n /** Label text colour for this category (replaces `textSecondary`). */\n textColor?: string;\n}\n\n/** The `extra.poi` block: POI category design. */\nexport interface PoiDesign {\n /** Block schema version; currently always 1. */\n version: 1;\n /** Overrides by category id; empty = all built-in. */\n categories: Record<string, PoiCategoryDesign>;\n}\n\n/**\n * The valid category ids with their built-in dot colours, in presentation\n * order. LOCKSTEP: mirrors `POI_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CATEGORY_COLORS: readonly (readonly [string, string])[] = [\n [\"food_drink\", \"#e8734a\"],\n [\"shopping\", \"#4a90d9\"],\n [\"transport\", \"#3a86ff\"],\n [\"lodging\", \"#9b6dd6\"],\n [\"health\", \"#e05c6c\"],\n [\"culture_leisure\", \"#3aa675\"],\n [\"education\", \"#d9a13a\"],\n [\"services\", \"#7a8699\"],\n];\n\n/** The valid category ids, in presentation order. */\nexport const POI_CATEGORY_IDS: readonly string[] = POI_CATEGORY_COLORS.map(([id]) => id);\n\n/**\n * OpenMapTiles `poi` layer `class` values grouped into the categories\n * above; every class not listed falls through to `services`. LOCKSTEP:\n * mirrors `POI_CLASS_CATEGORIES` in `website/lib/poi-icons.ts`.\n */\nexport const POI_CLASS_CATEGORIES: Record<string, string[]> = {\n food_drink: [\n \"restaurant\",\n \"fast_food\",\n \"cafe\",\n \"bar\",\n \"pub\",\n \"biergarten\",\n \"food_court\",\n \"alcohol_shop\",\n ],\n shopping: [\n \"shop\",\n \"grocery\",\n \"supermarket\",\n \"clothing_store\",\n \"mall\",\n \"department_store\",\n \"convenience\",\n \"bakery\",\n \"marketplace\",\n ],\n transport: [\n \"railway\",\n \"railway_station\",\n \"subway\",\n \"bus\",\n \"bus_station\",\n \"ferry_terminal\",\n \"aerodrome\",\n \"airport\",\n \"airfield\",\n ],\n lodging: [\n \"lodging\",\n \"hotel\",\n \"motel\",\n \"hostel\",\n \"guest_house\",\n \"camp_site\",\n \"caravan_site\",\n \"alpine_hut\",\n ],\n health: [\"hospital\", \"pharmacy\", \"doctors\", \"dentist\", \"veterinary\", \"clinic\"],\n culture_leisure: [\n \"museum\",\n \"theatre\",\n \"cinema\",\n \"attraction\",\n \"park\",\n \"stadium\",\n \"art_gallery\",\n \"zoo\",\n \"swimming_pool\",\n \"golf\",\n \"playground\",\n \"cemetery\",\n \"garden\",\n \"picnic_site\",\n \"viewpoint\",\n ],\n education: [\"school\", \"college\", \"university\", \"library\", \"kindergarten\"],\n services: [\n \"bank\",\n \"post\",\n \"police\",\n \"town_hall\",\n \"place_of_worship\",\n \"courthouse\",\n \"embassy\",\n \"fire_station\",\n \"community_centre\",\n \"toilet\",\n \"telephone\",\n \"atm\",\n ],\n};\n\n/** The built-in dot colour for a category id. */\nexport function builtInPoiColor(categoryId: string): string | undefined {\n return POI_CATEGORY_COLORS.find(([id]) => id === categoryId)?.[1];\n}\n\n/** No overrides: every category keeps its built-in dot and label colours. */\nexport function defaultPoiDesign(): PoiDesign {\n return { version: 1, categories: {} };\n}\n\n/** True when the design changes nothing. */\nexport function poiDesignIsDefault(design: PoiDesign): boolean {\n return Object.keys(design.categories).length === 0;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Cheap CSS colour check (hex forms + functional notations), mirroring\n * `isCssColour` in style.ts / `website/lib/studio-style.ts`.\n */\nfunction colour(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n if (t.startsWith(\"#\")) {\n const hex = t.slice(1);\n return [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex) ? t : undefined;\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (t.startsWith(prefix) && t.endsWith(\")\")) return t;\n }\n return undefined;\n}\n\n/**\n * Lenient parse of an `extra.poi` value: unknown category ids and invalid\n * colours are dropped rather than failing, so an imported theme never\n * breaks on its POI block. LOCKSTEP: identical semantics to\n * `parsePoiDesign` in `website/lib/studio-poi.ts`.\n */\nexport function parsePoiDesign(value: unknown): PoiDesign {\n const design = defaultPoiDesign();\n if (!isRecord(value) || !isRecord(value.categories)) return design;\n for (const id of POI_CATEGORY_IDS) {\n const raw = value.categories[id];\n if (!isRecord(raw)) continue;\n const category: PoiCategoryDesign = {};\n const color = colour(raw.color);\n const textColor = colour(raw.textColor);\n if (color !== undefined) category.color = color;\n if (textColor !== undefined) category.textColor = textColor;\n if (Object.keys(category).length > 0) design.categories[id] = category;\n }\n return design;\n}\n\n/**\n * Reads and parses the `extra.poi` block from a Studio theme document.\n * Returns `undefined` when the theme carries no poi block at all (so\n * callers can tell \"no design\" apart from \"default design\"); a present but\n * malformed block parses leniently to the defaults. Same contract as\n * `navDesignFromTheme`.\n */\nexport function poiDesignFromTheme(theme: Theme | undefined | null): PoiDesign | undefined {\n const extra = theme?.extra;\n if (typeof extra !== \"object\" || extra === null || !(\"poi\" in extra)) {\n return undefined;\n }\n return parsePoiDesign((extra as { poi?: unknown }).poi);\n}\n\n/**\n * Fetches a hosted theme document and reads its `extra.poi` block - point\n * it at the gateway's public, never-cached theme endpoint, e.g.\n * `https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme`. Returns\n * `undefined` when the theme carries no poi block; throws on network\n * failure, a non-2xx response or a non-JSON body. Same contract as\n * {@link navDesignFromThemeUrl}.\n *\n * @param fetchImpl Optional `fetch` replacement (tests, Node polyfills).\n */\nexport async function poiDesignFromThemeUrl(\n url: string,\n fetchImpl?: typeof fetch,\n): Promise<PoiDesign | undefined> {\n // Wrap rather than alias the global so browsers keep their `this` binding.\n const doFetch = fetchImpl ?? ((input: RequestInfo | URL) => globalThis.fetch(input));\n const response = await doFetch(url);\n if (!response.ok) {\n throw new Error(`fetching theme ${url}: HTTP ${response.status}`);\n }\n const theme = (await response.json()) as Theme;\n return poiDesignFromTheme(theme);\n}\n\n/**\n * The `poi-labels` `text-color` value for a design: the plain fallback\n * colour when no category overrides label text, otherwise a `match`\n * expression keyed on the tile's `class` property. Every non-services\n * category always gets an arm (override or fallback) so unmatched classes\n * - the `services` fallback arm - never inherit another category's colour.\n * LOCKSTEP: mirrors `poiTextColorExpression` in `website/lib/studio-poi.ts`.\n */\nexport function poiTextColorExpression(design: PoiDesign, fallback: string): unknown {\n if (!POI_CATEGORY_IDS.some((id) => design.categories[id]?.textColor)) return fallback;\n const arms = POI_CATEGORY_IDS.filter((id) => id !== \"services\").flatMap((id) => [\n POI_CLASS_CATEGORIES[id],\n design.categories[id]?.textColor ?? fallback,\n ]);\n return [\n \"match\",\n [\"get\", \"class\"],\n ...arms,\n design.categories.services?.textColor ?? fallback,\n ];\n}\n\n/** The subset of the MapLibre map surface {@link applyPoiDesign} touches. */\ninterface PoiPaintMap {\n getStyle(): { layers?: { id: string; type?: string }[] } | undefined;\n setPaintProperty(layerId: string, name: string, value: unknown): unknown;\n}\n\n/**\n * Applies a design's per-category label text colours to every `poi-labels`\n * layer on a live map (including per-territory clones named\n * `poi-labels@<territory>`). `fallbackTextColor` is the colour\n * non-overridden categories keep - pass the style's `poi-labels` text\n * colour (the theme's `textSecondary` slot; defaults to the light-base\n * value). A default design restores the plain fallback, so this is safe to\n * call on every design change.\n *\n * NOTE: runtime paint changes do not survive a later `setStyle`; re-apply\n * after style swaps (the MapMap website bakes the expression into the\n * style object instead for exactly this reason).\n */\nexport function applyPoiDesign(\n map: PoiPaintMap,\n design: PoiDesign,\n fallbackTextColor = \"#6b6b6b\",\n): void {\n const value = poiTextColorExpression(design, fallbackTextColor);\n for (const layer of map.getStyle()?.layers ?? []) {\n if (layer.id === \"poi-labels\" || layer.id.startsWith(\"poi-labels@\")) {\n map.setPaintProperty(layer.id, \"text-color\", value);\n }\n }\n}\n","/**\n * MapMap style assembly - pure, browser-free port of the `sn-style` crate.\n *\n * This module mirrors `crates/sn-style` (theme.rs + compile.rs), the\n * canonical MapMap Studio theme engine, so client-side and build-side\n * styles compile identically. A {@link Theme} is a small, agent-friendly\n * JSON document (named palette slots + per-layer overrides) that\n * {@link buildStyle} turns into a full MapLibre style-spec v8 style over\n * the MapMap territory tiles (OpenMapTiles schema, as emitted by\n * `sn-factory`'s Planetiler stage and served as PMTiles).\n *\n * The `pmtiles://` URL prefix is resolved by the pmtiles protocol handler\n * that {@link registerPmtilesProtocol} installs on the MapLibre instance.\n *\n * Attribution: \"© OpenStreetMap contributors\" (ODbL) and \"© OpenMapTiles\"\n * (CC-BY 4.0 schema) are legally required and stamped on every compiled\n * style's tile source. There is no theme field that can remove them.\n */\nimport type { StyleSpecification } from \"maplibre-gl\";\n\n/** A loose JSON object - skeleton layers are assembled as plain JSON. */\ntype JsonObject = Record<string, unknown>;\n\n/** Which built-in palette a theme starts from. */\nexport type MapMapTheme = \"light\" | \"dark\";\n\n/** The OSM attribution string. Legally required (ODbL) - never removed. */\nexport const OSM_ATTRIBUTION = \"© OpenStreetMap contributors\";\n\n/** The OpenMapTiles schema attribution (CC-BY 4.0). */\nexport const OPENMAPTILES_ATTRIBUTION = \"© OpenMapTiles\";\n\n/**\n * Combined attribution stamped on every compiled style's tile source.\n * Legally required (ODbL + CC-BY) - enforced, not themable: no theme\n * field can remove it.\n */\nexport const FULL_ATTRIBUTION = \"© OpenStreetMap contributors © OpenMapTiles\";\n\n/** Default glyph endpoint (PBF fontstacks), mirroring `sn_style::DEFAULT_GLYPHS_URL`. */\nexport const DEFAULT_GLYPHS_URL = \"https://fonts.mapmap.ai/{fontstack}/{range}.pbf\";\n\n/** A sensible default territory tiles URL (overridable per map). */\nexport const DEFAULT_TERRITORY_TILES_URL =\n \"pmtiles://https://tiles.mapmap.ai/territories/planet.pmtiles\";\n\n/**\n * Every source-layer the Planetiler (OpenMapTiles-schema) tiles emit.\n * The style skeleton covers all of them; extra layers referencing anything\n * else are rejected. Mirrors `sn_style::SOURCE_LAYERS`.\n */\nexport const SOURCE_LAYERS: readonly string[] = [\n \"aerodrome_label\",\n \"aeroway\",\n \"boundary\",\n \"building\",\n \"housenumber\",\n \"landcover\",\n \"landuse\",\n \"mountain_peak\",\n \"park\",\n \"place\",\n \"poi\",\n \"transportation\",\n \"transportation_name\",\n \"water\",\n \"water_name\",\n \"waterway\",\n];\n\n/**\n * The named palette slots as `[slot, lightDefault, darkDefault]`, mirroring\n * `sn_style::palette_slots()`. Order is stable and documentation-worthy: it\n * is the order a Studio UI should present them in.\n */\nexport const PALETTE_SLOTS: readonly (readonly [string, string, string])[] = [\n [\"background\", \"#f4f2ee\", \"#12161c\"],\n [\"water\", \"#a8c8e8\", \"#1b2c40\"],\n [\"waterway\", \"#a8c8e8\", \"#1b2c40\"],\n [\"landcover\", \"#e3e8dd\", \"#182029\"],\n [\"landuse\", \"#ece8e1\", \"#171e26\"],\n [\"park\", \"#cfe4c8\", \"#1a2a1f\"],\n [\"building\", \"#e2ddd4\", \"#20272f\"],\n [\"aeroway\", \"#dcd9d2\", \"#232b34\"],\n [\"road\", \"#ffffff\", \"#2b333d\"],\n [\"roadMajor\", \"#f6d9a0\", \"#4a5461\"],\n [\"path\", \"#d9d4ca\", \"#2a323c\"],\n [\"rail\", \"#d0cbc2\", \"#262e37\"],\n [\"boundary\", \"#b9a6c9\", \"#4a3d57\"],\n [\"boundaryMinor\", \"#c9bcd6\", \"#3a3247\"],\n [\"textPrimary\", \"#3a3a3a\", \"#d6dbe1\"],\n [\"textSecondary\", \"#6b6b6b\", \"#9aa3ad\"],\n [\"textHalo\", \"#ffffff\", \"#12161c\"],\n];\n\n/**\n * Per-layer override: merged onto the skeleton layer with the same id.\n * Mirrors `sn_style::LayerOverride`.\n */\nexport interface LayerOverride {\n /** Hide the layer entirely (`layout.visibility = \"none\"`). */\n visible?: boolean;\n /** Paint properties merged over the skeleton's (per-key, override wins). */\n paint?: Record<string, unknown>;\n /** Layout properties merged over the skeleton's. */\n layout?: Record<string, unknown>;\n /** Replace the skeleton's filter (per-attribute styling hook). */\n filter?: unknown;\n minzoom?: number;\n maxzoom?: number;\n}\n\n/**\n * The optional visual-effects block, mirroring `sn_style::Effects`. Unlike\n * `extra`, this IS carried into the compiled style — as\n * `metadata[\"mapmap:effects\"]` — so any consumer of a compiled `style.json`\n * (hosted style URL, baked territory package) can honour it without the\n * theme document. Renderers that do not know the effects engine ignore the\n * metadata and render the style unchanged.\n */\nexport interface ThemeEffects {\n /** Route-line effect: `\"flow\"` (animated energy ribbon) or `\"none\"`. */\n route?: \"flow\" | \"none\";\n /**\n * Effect parameters, validated per effect. For `flow`: `color` (CSS\n * colour), `width` (px, 0.5-40), `speed` (cycles/s, 0-10).\n */\n params?: Record<string, unknown>;\n}\n\n/** The accepted `params` keys for the `flow` effect. */\nconst FLOW_PARAM_KEYS: readonly string[] = [\"color\", \"width\", \"speed\"];\n\n/**\n * Validate a theme's effects block, mirroring\n * `sn_style::theme::validate_effects` (same agent-readable messages).\n */\nfunction validateEffects(effects: ThemeEffects): void {\n const route = effects.route ?? \"none\";\n if (route !== \"flow\" && route !== \"none\") {\n throw new Error(\n `invalid effects block: unknown route effect ${JSON.stringify(route)}; ` +\n 'accepted: \"flow\", \"none\"',\n );\n }\n if (!effects.params) return;\n if (route === \"none\") {\n throw new Error(\n 'invalid effects block: \"params\" requires \"route\" to name an effect (e.g. \"flow\")',\n );\n }\n for (const [key, value] of Object.entries(effects.params)) {\n if (key === \"color\") {\n if (typeof value !== \"string\" || !isCssColour(value)) {\n throw new Error(\n `invalid effects block: params.color has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n } else if (key === \"width\") {\n if (typeof value !== \"number\" || value < 0.5 || value > 40) {\n throw new Error(\n \"invalid effects block: params.width must be a number between \" +\n `0.5 and 40 (pixels), got ${JSON.stringify(value)}`,\n );\n }\n } else if (key === \"speed\") {\n if (typeof value !== \"number\" || value < 0 || value > 10) {\n throw new Error(\n \"invalid effects block: params.speed must be a number between \" +\n `0 and 10 (cycles per second), got ${JSON.stringify(value)}`,\n );\n }\n } else {\n throw new Error(\n `invalid effects block: unknown params key ${JSON.stringify(key)}; ` +\n `accepted keys: ${FLOW_PARAM_KEYS.join(\", \")}`,\n );\n }\n }\n}\n\n/**\n * A MapMap Studio theme: the unit users and agents edit, store and publish.\n * Mirrors `sn_style::Theme` (all fields carry serde defaults, so everything\n * is optional here).\n */\nexport interface Theme {\n /** Human-readable theme name, e.g. `\"midnight-fleet\"`. */\n name?: string;\n /** Built-in palette to start from. Defaults to `\"light\"`. */\n base?: MapMapTheme;\n /** Palette overrides by slot name (see {@link PALETTE_SLOTS}). */\n palette?: Record<string, string>;\n /** Per-layer overrides by skeleton layer id. */\n layers?: Record<string, LayerOverride>;\n /**\n * Render buildings as 3D extrusions. Adds a `building-3d` fill-extrusion\n * layer (zoom 15+) driven by the tiles' `render_height` /\n * `render_min_height` attributes, and caps the flat `building` footprint\n * layer at that zoom so the two hand off cleanly (the extrusion rises\n * from flat as you zoom in). Web-safe; native navigation SDKs should\n * leave this off by default until MapLibre Native's fill-extrusion\n * memory use at street zooms is fixed (maplibre-native#4107). Mirrors\n * `Theme::buildings_3d`.\n */\n buildings_3d?: boolean;\n /**\n * Label fonts. Every fontstack must exist on the glyph server; until that\n * ships (P2), leave this at its default (`\"Noto Sans Regular\"`).\n */\n fonts?: { regular?: string };\n /** Override the glyph endpoint (defaults to {@link DEFAULT_GLYPHS_URL}). */\n glyphs?: string;\n /** Optional sprite URL (icons/shields - P2, no default sprite exists). */\n sprite?: string;\n /**\n * Extra fully-formed MapLibre layers appended above the skeleton (below\n * labels). Each must reference the `territory` source and a known\n * source-layer.\n */\n extra_layers?: JsonObject[];\n /**\n * Optional visual effects (route ribbon etc.). Compiled into\n * `metadata[\"mapmap:effects\"]` on the style — see {@link ThemeEffects}.\n * Mirrors `Theme::effects`.\n */\n effects?: ThemeEffects;\n /**\n * Non-style extras carried by the THEME DOCUMENT, not the compiled\n * style. Studio stores its navigation design block here (`extra.nav`;\n * see `nav-design.ts`) and its POI category design (`extra.poi`; see\n * `poi-design.ts`). {@link buildStyle} ignores it entirely - the\n * compiled `style.json` is byte-identical with or without it. Mirrors\n * `Theme::extra` in the canonical Rust crate: the hosted styles API\n * stores the block verbatim (bounded at 256 KB serialised) and serves it\n * back from `GET /styles/{id}/theme`, so a Studio design survives\n * publishing - consume it via `createMap` with a theme document or\n * `navDesignFromThemeUrl` / `poiDesignFromThemeUrl` with the hosted\n * theme URL.\n */\n extra?: { nav?: unknown; poi?: unknown };\n}\n\nexport interface BuildStyleOptions {\n /**\n * Label language: an ISO 639 code selects `name:<code>` with a\n * local-name fallback; the literal `\"local\"` selects the local name\n * outright; omitted keeps the default (English-first). The tiles carry\n * the OSM `name:*` set, so switching involves no tile rebuild.\n */\n labelLanguage?: string;\n /**\n * Theme to build: a built-in name (`\"light\"` / `\"dark\"`) or a full\n * {@link Theme} document. Defaults to `\"light\"`.\n */\n theme?: MapMapTheme | Theme;\n /**\n * PMTiles URL for the territory tiles. Accepts either a `pmtiles://…` URL\n * or a plain `https://…` URL (the `pmtiles://` prefix is added for you).\n */\n territoryTilesUrl?: string;\n}\n\n/** Ensure a tiles URL carries the `pmtiles://` protocol prefix. */\nexport function toPmtilesUrl(url: string): string {\n return url.startsWith(\"pmtiles://\") ? url : `pmtiles://${url}`;\n}\n\n/**\n * Cheap CSS colour check: hex forms and the functional notations MapLibre\n * accepts. Deliberately permissive on the inside of `rgb()`/`hsl()`.\n * Mirrors `sn_style::theme::is_css_colour`.\n */\nfunction isCssColour(value: string): boolean {\n const v = value.trim();\n if (v.startsWith(\"#\")) {\n const hex = v.slice(1);\n return (\n [3, 4, 6, 8].includes(hex.length) && /^[0-9a-fA-F]+$/.test(hex)\n );\n }\n for (const prefix of [\"rgb(\", \"rgba(\", \"hsl(\", \"hsla(\"]) {\n if (v.startsWith(prefix) && v.endsWith(\")\")) return true;\n }\n return false;\n}\n\n/**\n * Resolve the effective palette for a theme: base defaults + overrides.\n * Fails on unknown slots or unparseable colours (agent self-correction).\n * Mirrors `sn_style::theme::resolve_palette`.\n */\nfunction resolvePalette(theme: Theme): Record<string, string> {\n const base = theme.base ?? \"light\";\n const palette: Record<string, string> = {};\n // Membership is checked against the slot list, not with `in` (which would\n // accept Object.prototype keys like \"toString\" that the Rust compiler\n // rejects as UnknownPaletteSlot).\n const knownSlots = new Set(PALETTE_SLOTS.map(([slot]) => slot));\n for (const [slot, light, dark] of PALETTE_SLOTS) {\n palette[slot] = base === \"dark\" ? dark : light;\n }\n for (const [slot, value] of Object.entries(theme.palette ?? {})) {\n if (!knownSlots.has(slot)) {\n const accepted = PALETTE_SLOTS.map(([s]) => s).join(\", \");\n throw new Error(\n `unknown palette slot ${JSON.stringify(slot)}; accepted slots: ${accepted}`,\n );\n }\n if (!isCssColour(value)) {\n throw new Error(\n `palette slot ${JSON.stringify(slot)} has invalid colour ` +\n `${JSON.stringify(value)}; use #rgb/#rrggbb/#rrggbbaa or ` +\n \"rgb()/rgba()/hsl()/hsla()\",\n );\n }\n palette[slot] = value;\n }\n return palette;\n}\n\n/** Skeleton fill layer, mirroring `compile.rs`'s `fill()` helper. */\nfunction fill(\n id: string,\n sourceLayer: string,\n colour: string,\n opacity: number,\n minzoom?: number,\n): JsonObject {\n const layer: JsonObject = {\n id,\n type: \"fill\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n paint: { \"fill-color\": colour, \"fill-opacity\": opacity },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Skeleton symbol layer, mirroring `compile.rs`'s `symbol()` helper. */\nfunction symbol(\n id: string,\n sourceLayer: string,\n textField: unknown,\n font: readonly string[],\n textSize: unknown,\n colour: string,\n halo: string,\n minzoom?: number,\n extraLayout?: JsonObject,\n): JsonObject {\n const layout: JsonObject = {\n \"text-field\": textField,\n \"text-font\": font,\n \"text-size\": textSize,\n ...extraLayout,\n };\n const layer: JsonObject = {\n id,\n type: \"symbol\",\n source: \"territory\",\n \"source-layer\": sourceLayer,\n layout,\n paint: {\n \"text-color\": colour,\n \"text-halo-color\": halo,\n \"text-halo-width\": 1.2,\n },\n };\n if (minzoom !== undefined) layer[\"minzoom\"] = minzoom;\n return layer;\n}\n\n/** Apply a per-layer override, mirroring `compile.rs`'s `apply_override`. */\nfunction applyOverride(layer: JsonObject, layerOverride: LayerOverride): void {\n if (layerOverride.paint) mergeObject(layer, \"paint\", layerOverride.paint);\n if (layerOverride.layout) mergeObject(layer, \"layout\", layerOverride.layout);\n if (layerOverride.filter !== undefined) layer[\"filter\"] = layerOverride.filter;\n if (layerOverride.minzoom !== undefined) layer[\"minzoom\"] = layerOverride.minzoom;\n if (layerOverride.maxzoom !== undefined) layer[\"maxzoom\"] = layerOverride.maxzoom;\n if (layerOverride.visible === false) {\n const layout = (layer[\"layout\"] ??= {}) as JsonObject;\n layout[\"visibility\"] = \"none\";\n }\n}\n\nfunction mergeObject(\n layer: JsonObject,\n key: \"paint\" | \"layout\",\n overrides: Record<string, unknown>,\n): void {\n const target = (layer[key] ??= {}) as JsonObject;\n for (const [k, v] of Object.entries(overrides)) target[k] = v;\n}\n\n/** Validate one extra layer, mirroring `compile.rs`'s `validate_extra_layer`. */\nfunction validateExtraLayer(index: number, layer: unknown): JsonObject {\n const invalid = (reason: string): Error =>\n new Error(`extra layer ${index} is invalid: ${reason}`);\n if (typeof layer !== \"object\" || layer === null || Array.isArray(layer)) {\n throw invalid(\"must be an object\");\n }\n const obj = layer as JsonObject;\n const id = obj[\"id\"];\n if (typeof id !== \"string\") throw invalid('must have a string \"id\"');\n if (id.length === 0) throw invalid('\"id\" must be non-empty');\n if (obj[\"type\"] !== \"background\") {\n if (obj[\"source\"] !== \"territory\") {\n throw invalid('\"source\" must be \"territory\"');\n }\n const sourceLayer = obj[\"source-layer\"];\n if (typeof sourceLayer !== \"string\") {\n throw invalid('must have a string \"source-layer\"');\n }\n if (!SOURCE_LAYERS.includes(sourceLayer)) {\n throw invalid(\n `unknown source-layer ${JSON.stringify(sourceLayer)}; accepted: ` +\n SOURCE_LAYERS.join(\", \"),\n );\n }\n }\n return obj;\n}\n\n/**\n * Assemble a full MapLibre style for the MapMap tiles - a faithful port of\n * `sn_style::compile`, so a {@link Theme} compiles to the same style here\n * as it does in `sn-factory`/`sn-gateway`. Pure: returns a plain object,\n * touches no browser APIs, and is safe to snapshot in tests.\n *\n * Throws an `Error` with an agent-readable message (offending key + the\n * accepted values) on unknown palette slots, invalid colours, unknown layer\n * ids and invalid extra layers, mirroring `sn_style::StyleError`.\n */\n/**\n * The accepted top-level {@link Theme} keys (mirrors serde\n * `deny_unknown_fields`). `extra` is the one deliberate divergence from the\n * Rust crate: it carries Studio's nav design block in the theme FILE and is\n * ignored by compilation (the gateway still rejects it on `/styles`, which\n * is why Studio strips it on publish).\n */\nconst THEME_KEYS: readonly string[] = [\n \"name\",\n \"base\",\n \"palette\",\n \"layers\",\n \"fonts\",\n \"glyphs\",\n \"sprite\",\n \"extra_layers\",\n \"extra\",\n \"buildings_3d\",\n \"effects\",\n];\n\n/**\n * The `metadata` key a compiled style carries its effects block under.\n * Shared with `sn-style` (compile.rs) and read back by `MapMapMap` to\n * auto-enable the route effect for styles that request one.\n */\nexport const EFFECTS_METADATA_KEY = \"mapmap:effects\";\n\n/**\n * The effects block from a compiled style's `metadata`, if the style\n * carries a valid one (`{ route: \"flow\", params? }`). Lenient by design —\n * it reads FOREIGN styles (hosted URLs, baked packages), so anything\n * malformed returns `undefined` rather than throwing.\n */\nexport function effectsFromStyleMetadata(\n metadata: unknown,\n): { route: \"flow\"; params?: Record<string, unknown> } | undefined {\n if (typeof metadata !== \"object\" || metadata === null) return undefined;\n const block = (metadata as JsonObject)[EFFECTS_METADATA_KEY];\n if (typeof block !== \"object\" || block === null) return undefined;\n const { route, params } = block as JsonObject;\n if (route !== \"flow\") return undefined;\n return typeof params === \"object\" && params !== null\n ? { route, params: params as Record<string, unknown> }\n : { route };\n}\n\n/**\n * Zoom at which 3D building extrusions start (and the flat footprint layer\n * stops) when a theme sets `buildings_3d`. Mirrors\n * `compile.rs::BUILDINGS_3D_MINZOOM`. Exported for\n * `MapMapMap.setBuildings3d`, which performs the same handoff at runtime.\n */\nexport const BUILDINGS_3D_MINZOOM = 15;\n\n/**\n * The `building-3d` fill-extrusion layer a theme with `buildings_3d` gets:\n * heights from the tiles' `render_height`/`render_min_height` (5 m coalesce\n * fallback for tiles missing them), rising from flat over half a zoom so\n * the handoff from the footprint layer is seamless. Mirrors the layer\n * `compile.rs` emits, byte for byte. Shared by {@link buildStyle} and\n * `MapMapMap.setBuildings3d` so the two can never drift.\n */\nexport function buildings3dLayer(colour: unknown): JsonObject {\n return {\n id: \"building-3d\",\n type: \"fill-extrusion\",\n source: \"territory\",\n \"source-layer\": \"building\",\n minzoom: BUILDINGS_3D_MINZOOM,\n paint: {\n \"fill-extrusion-color\": colour,\n \"fill-extrusion-height\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_height\"], 5],\n ],\n \"fill-extrusion-base\": [\n \"interpolate\",\n [\"linear\"],\n [\"zoom\"],\n BUILDINGS_3D_MINZOOM,\n 0,\n BUILDINGS_3D_MINZOOM + 0.5,\n [\"coalesce\", [\"get\", \"render_min_height\"], 0],\n ],\n \"fill-extrusion-opacity\": 0.85,\n \"fill-extrusion-vertical-gradient\": true,\n },\n };\n}\n\n/** The `text-field` expression for the requested label language. */\nfunction nameFieldFor(labelLanguage?: string): unknown {\n if (labelLanguage === \"local\") return [\"get\", \"name\"];\n if (labelLanguage) return [\"coalesce\", [\"get\", `name:${labelLanguage}`], [\"get\", \"name\"]];\n return [\"coalesce\", [\"get\", \"name:en\"], [\"get\", \"name\"]];\n}\n\nexport function buildStyle(options: BuildStyleOptions = {}): StyleSpecification {\n const input = options.theme ?? \"light\";\n if (typeof input === \"object\") {\n // Mirror the Rust Theme's serde deny_unknown_fields: a typo'd key\n // (e.g. \"extraLayers\", \"pallete\") must fail loudly here too, not\n // silently render the default style.\n for (const key of Object.keys(input)) {\n if (!THEME_KEYS.includes(key)) {\n throw new Error(\n `unknown theme field ${JSON.stringify(key)}; accepted fields: ` +\n THEME_KEYS.join(\", \"),\n );\n }\n }\n }\n const theme: Theme =\n typeof input === \"string\" ? { name: input, base: input } : input;\n const palette = resolvePalette(theme);\n const p = (slot: string): string => palette[slot] as string;\n const font = [theme.fonts?.regular ?? \"Noto Sans Regular\"] as const;\n const nameField = nameFieldFor(options.labelLanguage);\n const tilesUrl = toPmtilesUrl(\n options.territoryTilesUrl ?? DEFAULT_TERRITORY_TILES_URL,\n );\n\n // The skeleton: every OpenMapTiles source-layer styled, palette-driven.\n // Order is paint order (first = bottom). Mirrors compile.rs exactly.\n const layers: JsonObject[] = [\n {\n id: \"background\",\n type: \"background\",\n paint: { \"background-color\": p(\"background\") },\n },\n fill(\"landcover\", \"landcover\", p(\"landcover\"), 0.6),\n fill(\"landuse\", \"landuse\", p(\"landuse\"), 0.45),\n fill(\"park\", \"park\", p(\"park\"), 0.7),\n fill(\"water\", \"water\", p(\"water\"), 1.0),\n {\n id: \"waterway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"waterway\",\n paint: {\n \"line-color\": p(\"waterway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 3],\n },\n },\n {\n id: \"aeroway\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"aeroway\",\n minzoom: 10,\n filter: [\"in\", \"class\", \"runway\", \"taxiway\"],\n paint: {\n \"line-color\": p(\"aeroway\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 10, 1, 16, 6],\n },\n },\n fill(\"building\", \"building\", p(\"building\"), 0.9, 13),\n {\n id: \"rail\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 8,\n filter: [\"in\", \"class\", \"rail\", \"transit\"],\n paint: {\n \"line-color\": p(\"rail\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.4, 16, 2],\n },\n },\n {\n id: \"road-path\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n minzoom: 13,\n filter: [\"in\", \"class\", \"path\", \"track\", \"pedestrian\"],\n paint: {\n \"line-color\": p(\"path\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 13, 0.5, 16, 2],\n \"line-dasharray\": [2, 1],\n },\n },\n {\n id: \"road-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\n \"!in\",\n \"class\",\n \"motorway\",\n \"trunk\",\n \"primary\",\n \"rail\",\n \"transit\",\n \"path\",\n \"track\",\n \"pedestrian\",\n \"ferry\",\n ],\n paint: {\n \"line-color\": p(\"road\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 0.5, 16, 4],\n },\n },\n {\n id: \"road-major\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"transportation\",\n filter: [\"in\", \"class\", \"motorway\", \"trunk\", \"primary\"],\n paint: {\n \"line-color\": p(\"roadMajor\"),\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 6, 1, 16, 8],\n },\n },\n {\n id: \"boundary-minor\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n minzoom: 6,\n filter: [\"all\", [\">=\", \"admin_level\", 3], [\"<=\", \"admin_level\", 8]],\n paint: {\n \"line-color\": p(\"boundaryMinor\"),\n \"line-width\": 0.6,\n \"line-dasharray\": [2, 2],\n },\n },\n {\n id: \"boundary\",\n type: \"line\",\n source: \"territory\",\n \"source-layer\": \"boundary\",\n filter: [\"<=\", \"admin_level\", 2],\n paint: {\n \"line-color\": p(\"boundary\"),\n \"line-width\": 1,\n \"line-dasharray\": [3, 2],\n },\n },\n ];\n\n // 3D buildings: a fill-extrusion layer above the road network (2D layers\n // drawn after an extrusion paint over its pitched volumes, so it must\n // come last in the base map), below extras and labels. The flat\n // footprint layer is capped at the extrusion minzoom. Mirrors compile.rs.\n if (theme.buildings_3d) {\n const flat = layers.find((l) => l[\"id\"] === \"building\") as JsonObject;\n flat[\"maxzoom\"] = BUILDINGS_3D_MINZOOM;\n layers.push(buildings3dLayer(p(\"building\")));\n }\n\n // User/agent-supplied extra layers sit above the base map, below labels.\n (theme.extra_layers ?? []).forEach((extra, index) => {\n layers.push(structuredClone(validateExtraLayer(index, extra)));\n });\n\n layers.push(\n symbol(\n \"housenumber\",\n \"housenumber\",\n [\"get\", \"housenumber\"],\n font,\n 10,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 17,\n ),\n symbol(\n \"road-labels\",\n \"transportation_name\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 12,\n { \"symbol-placement\": \"line\" },\n ),\n symbol(\n \"water-name\",\n \"water_name\",\n nameField,\n font,\n 12,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"poi-labels\",\n \"poi\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 14,\n { \"text-anchor\": \"top\" },\n ),\n symbol(\n \"mountain-peak-labels\",\n \"mountain_peak\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n ),\n symbol(\n \"aerodrome-labels\",\n \"aerodrome_label\",\n nameField,\n font,\n 11,\n p(\"textSecondary\"),\n p(\"textHalo\"),\n 10,\n ),\n // Label hierarchy: settlements and regions wait until z4 so world\n // zooms aren't a flat democracy of states, cities and villages;\n // continent labels are dropped entirely as clutter.\n {\n ...symbol(\n \"place-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 4, 10.5, 12, 16],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 4,\n ),\n filter: [\"match\", [\"get\", \"class\"], [\"country\", \"continent\"], false, true],\n },\n // Countries: the most prominent text on the map at world zooms —\n // larger, letter-spaced, visible from z1, ceding to the regional\n // hierarchy from z10. Drawn last = wins label collisions.\n {\n ...symbol(\n \"country-labels\",\n \"place\",\n nameField,\n font,\n [\"interpolate\", [\"linear\"], [\"zoom\"], 1, 11, 3, 13.5, 6, 18],\n p(\"textPrimary\"),\n p(\"textHalo\"),\n 1,\n { \"text-letter-spacing\": 0.08, \"text-max-width\": 7 },\n ),\n filter: [\"==\", [\"get\", \"class\"], \"country\"],\n maxzoom: 10,\n },\n );\n\n // Reject duplicate layer ids (e.g. an extra layer reusing a skeleton id),\n // mirroring `validate_style` in sn-style's validate.rs — the Rust compiler\n // rejects these and MapLibre would error at style load.\n const seenIds = new Set<string>();\n for (const layer of layers) {\n const layerId = layer[\"id\"] as string;\n if (seenIds.has(layerId)) {\n throw new Error(`duplicate layer id ${JSON.stringify(layerId)}`);\n }\n seenIds.add(layerId);\n }\n\n // Apply per-layer overrides.\n const accepted = layers.map((l) => l[\"id\"] as string).join(\", \");\n for (const [id, layerOverride] of Object.entries(theme.layers ?? {})) {\n const layer = layers.find((l) => l[\"id\"] === id);\n if (!layer) {\n throw new Error(\n `unknown layer id ${JSON.stringify(id)}; accepted ids: ${accepted}`,\n );\n }\n applyOverride(layer, layerOverride);\n }\n\n const style: JsonObject = {\n version: 8,\n name: theme.name ? `MapMap ${theme.name}` : \"MapMap\",\n glyphs: theme.glyphs ?? DEFAULT_GLYPHS_URL,\n sources: {\n territory: {\n type: \"vector\",\n url: tilesUrl,\n // Legally required (ODbL + CC-BY) - enforced, not themable. There\n // is no theme field that can remove it.\n attribution: FULL_ATTRIBUTION,\n },\n },\n layers,\n };\n if (theme.sprite !== undefined) style[\"sprite\"] = theme.sprite;\n\n // Effects ride the COMPILED style (unlike `extra`, which is theme-only):\n // `metadata[\"mapmap:effects\"]` is the one channel a hosted style URL or a\n // baked territory package carries, so `MapMapMap` can auto-enable the\n // route ribbon from the style alone. Mirrors compile.rs.\n if (theme.effects) {\n validateEffects(theme.effects);\n if ((theme.effects.route ?? \"none\") !== \"none\") {\n const block: JsonObject = { route: theme.effects.route };\n if (theme.effects.params) block[\"params\"] = theme.effects.params;\n style[\"metadata\"] = { [EFFECTS_METADATA_KEY]: block };\n }\n }\n\n // The object above is structurally a MapLibre style; the cast avoids\n // hand-satisfying every discriminated-union member of StyleSpecification.\n return style as unknown as StyleSpecification;\n}\n","/**\n * MapMapMap - the branded MapLibre GL map.\n *\n * A thin wrapper over `maplibregl.Map`. MapLibre does all the rendering; this\n * class only wires in the MapMap default style, registers the pmtiles\n * protocol, and keeps the gateway `apiKey`/`baseUrl` handy so routing and ADR\n * helpers can reuse them.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n LayerSpecification,\n Map as MlMap,\n MapOptions,\n StyleSpecification,\n} from \"maplibre-gl\";\nimport { Protocol } from \"pmtiles\";\nimport { runMapDiagnostics } from \"./diagnostics.js\";\nimport {\n createRouteEffect,\n type RouteEffectLayer,\n type RouteEffectName,\n type RouteFlowOptions,\n} from \"./effects.js\";\nimport { LogoControl, type LogoOptions } from \"./logo.js\";\nimport { navDesignFromTheme, type NavDesign } from \"./nav-design.js\";\nimport { poiDesignFromTheme, type PoiDesign } from \"./poi-design.js\";\nimport {\n BUILDINGS_3D_MINZOOM,\n buildStyle,\n buildings3dLayer,\n effectsFromStyleMetadata,\n type MapMapTheme,\n type Theme,\n} from \"./style.js\";\nimport type { RouteGeometry } from \"./types.js\";\n\n// Tracked per maplibre-gl module instance, not with a single flag: bundlers\n// can duplicate maplibre-gl, and each copy needs its own registration.\nconst pmtilesRegistered = new WeakSet<object>();\n\n/**\n * Register the `pmtiles://` protocol on a MapLibre instance. Idempotent per\n * maplibre-gl instance, and safe to call before constructing any map.\n * Exposed for apps that build their own `maplibregl.Map` (possibly from\n * their own bundled maplibre-gl copy) but still want to read MapMap PMTiles.\n */\nexport function registerPmtilesProtocol(gl: typeof maplibregl = maplibregl): void {\n if (pmtilesRegistered.has(gl)) return;\n const protocol = new Protocol();\n gl.addProtocol(\"pmtiles\", protocol.tile);\n pmtilesRegistered.add(gl);\n}\n\nexport interface MapMapOptions {\n /**\n * The MapMap wordmark on the map (like the Google Maps / Mapbox marks).\n * Default on at bottom-right, above the attribution; `false` removes\n * it, or pass `{ position, href }` to customise.\n */\n logo?: boolean | LogoOptions;\n /** The container element or its id. */\n container: string | HTMLElement;\n /** Gateway API key (`snk_…`), used by routing and ADR helpers. */\n apiKey?: string;\n /** Gateway base URL for routing/ADR. Defaults to `https://api.mapmap.ai`. */\n baseUrl?: string;\n /**\n * Style to load. A theme name (`\"light\"` / `\"dark\"`), a MapMap Studio\n * `Theme` document, a full MapLibre `StyleSpecification`, or a style URL.\n * Defaults to `\"light\"`.\n */\n style?: MapMapTheme | Theme | StyleSpecification | string;\n /** Override the territory PMTiles URL used by the default styles. */\n territoryTilesUrl?: string;\n /** Initial centre as `[lng, lat]`. Defaults to the UK. */\n center?: [number, number];\n /** Initial zoom. Defaults to `5`. */\n zoom?: number;\n /**\n * Extra MapLibre `MapOptions` merged last (escape hatch for hash, bearing,\n * maxBounds, etc.). `container` and `style` here are ignored.\n */\n mapOptions?: Partial<Omit<MapOptions, \"container\" | \"style\">>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.mapmap.ai\";\nconst DEFAULT_CENTER: [number, number] = [-1.5, 52.6];\nconst DEFAULT_ZOOM = 5;\nconst DEFAULT_EFFECT_LAYER_ID = \"mapmap-route-effect\";\n\n/** Options for {@link MapMapMap.setRouteEffect}. */\nexport interface SetRouteEffectOptions extends RouteFlowOptions {\n /**\n * The route line to attach the effect to. Optional: when omitted the\n * effect is ARMED and applies as soon as a `RouteLayer` draws a route\n * (RouteLayer feeds every drawn geometry to the map automatically).\n */\n geometry?: RouteGeometry;\n}\n\n/** The flow options carried by a style's `metadata[\"mapmap:effects\"].params`. */\nfunction flowOptionsFromParams(params: Record<string, unknown>): RouteFlowOptions {\n const options: RouteFlowOptions = {};\n if (typeof params[\"color\"] === \"string\") options.color = params[\"color\"];\n if (typeof params[\"width\"] === \"number\") options.width = params[\"width\"];\n if (typeof params[\"speed\"] === \"number\") options.speed = params[\"speed\"];\n return options;\n}\n\n/** The MapMap map: a branded, tiles-and-routing-ready MapLibre map. */\nexport class MapMapMap {\n /** The underlying MapLibre map. Use it for any native MapLibre call. */\n readonly map: MlMap;\n /** Gateway API key, if provided. */\n readonly apiKey: string | undefined;\n /** Gateway base URL (no trailing slash). */\n readonly baseUrl: string;\n /**\n * The Studio navigation design (`extra.nav`) parsed from the theme passed\n * as `style`, when it carried one. `RouteLayer`, `PositionPuck` and\n * `GuidanceBanner` pick this up as their default look; `undefined` means\n * the theme had no nav block (or `style` was not a theme document).\n */\n readonly navDesign: NavDesign | undefined;\n /**\n * The Studio POI category design (`extra.poi`) parsed from the theme\n * passed as `style`, when it carried one. Apply its label-text part with\n * `applyPoiDesign(map.map, map.poiDesign)`; `undefined` means the theme\n * had no poi block (or `style` was not a theme document).\n */\n readonly poiDesign: PoiDesign | undefined;\n\n // Route-effect state (see setRouteEffect / effects.ts). `explicit`\n // records an app-level decision, which always wins over a style's\n // metadata auto-enable.\n private effectName: RouteEffectName | null = null;\n private effectOptions: RouteFlowOptions = {};\n private effectGeometry: RouteGeometry | undefined;\n private effectExplicit = false;\n private effectLayer: RouteEffectLayer | undefined;\n\n constructor(options: MapMapOptions) {\n registerPmtilesProtocol();\n\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n const theme = themeOf(options.style);\n this.navDesign = navDesignFromTheme(theme);\n this.poiDesign = poiDesignFromTheme(theme);\n\n const style = resolveStyle(options.style, options.territoryTilesUrl);\n\n this.map = new maplibregl.Map({\n container: options.container,\n style,\n center: options.center ?? DEFAULT_CENTER,\n zoom: options.zoom ?? DEFAULT_ZOOM,\n attributionControl: { compact: false },\n ...options.mapOptions,\n });\n\n // The MapMap mark, Google/Mapbox-style. Default on (bottom-right,\n // above the attribution); `logo: false` removes it, `logo: {...}`\n // repositions it. Attribution is separate and never removable.\n if (options.logo !== false) {\n const logoOptions = options.logo === true ? {} : (options.logo ?? {});\n this.map.addControl(\n new LogoControl(logoOptions),\n logoOptions.position ?? \"bottom-right\",\n );\n }\n\n // Route effects: styles compiled with an `effects` block carry\n // `metadata[\"mapmap:effects\"]`; honour it on every style (re)load\n // unless the app has called setRouteEffect itself. Custom layers are\n // wiped by setStyle like all runtime layers, so this also re-installs\n // an active effect after a theme swap.\n this.map.on(\"style.load\", this.handleStyleLoadForEffects);\n\n // Self-diagnosing errors: one actionable console.error per issue per\n // page (0px container, duplicate maplibre-gl, WebGL, 401s). Fully\n // defensive - never throws, skips DOM checks server-side.\n runMapDiagnostics({\n container: options.container,\n map: this.map,\n maplibre: maplibregl,\n apiKey: this.apiKey,\n });\n }\n\n private readonly handleStyleLoadForEffects = (): void => {\n if (!this.effectExplicit) {\n const block = effectsFromStyleMetadata(this.styleMetadata());\n this.effectName = block?.route ?? null;\n this.effectOptions = block?.params ? flowOptionsFromParams(block.params) : {};\n }\n // The old layer object died with the old style; re-add a fresh one.\n // Deferred a microtask so layers other style.load handlers re-install\n // (RouteLayer's line) land first and the ribbon stays on top.\n this.effectLayer = undefined;\n queueMicrotask(() => this.applyRouteEffect());\n };\n\n /** The current style's `metadata`, if it can be read yet. */\n private styleMetadata(): unknown {\n try {\n return (\n this.map as { getStyle?: () => { metadata?: unknown } | undefined }\n ).getStyle?.()?.metadata;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Set (or clear) the visual effect on the active route line - the\n * effects-engine entry point (see `effects.ts`). The first effect is\n * `\"flow\"`: an animated energy ribbon flowing along the route, drawn in\n * a MapLibre custom layer with first-party GLSL.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * map.setRouteEffect(\"flow\"); // uses the drawn route\n * map.setRouteEffect(\"flow\", { color: \"#ff7a1f\" }); // options\n * map.setRouteEffect(null); // back to the plain line\n * ```\n *\n * Geometry: pass `{ geometry }` explicitly, or omit it and the effect\n * attaches to whatever route a `RouteLayer` on this map draws (current\n * and future - RouteLayer reports every drawn line via\n * {@link setRouteEffectGeometry}).\n *\n * Styles whose theme carried an `effects` block auto-enable their effect\n * from the compiled style's metadata; calling this method (with any\n * value, including `null`) overrides the style's wish for the lifetime\n * of this map.\n *\n * Accessibility/resilience (see effects.ts): honours\n * `prefers-reduced-motion` (static gradient, no animation) and falls\n * back to the plain route line with a single console warning if WebGL\n * setup fails.\n */\n setRouteEffect(\n effect: RouteEffectName | null,\n options: SetRouteEffectOptions = {},\n ): void {\n this.effectExplicit = true;\n const { geometry, ...flowOptions } = options;\n this.effectName = effect;\n this.effectOptions = flowOptions;\n if (geometry) this.effectGeometry = geometry;\n // Options are baked into the layer at creation; rebuild it.\n this.removeEffectLayer();\n this.applyRouteEffect();\n }\n\n /**\n * Attach the active route effect to a route line (or detach it with\n * `null`). `RouteLayer` calls this on every `draw()`/`clear()`, so apps\n * normally never do - pass `geometry` to {@link setRouteEffect} for\n * routes drawn outside a RouteLayer.\n */\n setRouteEffectGeometry(geometry: RouteGeometry | null): void {\n this.effectGeometry = geometry ?? undefined;\n if (\n geometry &&\n this.effectLayer &&\n this.map.getLayer(this.effectLayerId())\n ) {\n this.effectLayer.setGeometry(geometry);\n return;\n }\n this.applyRouteEffect();\n }\n\n private effectLayerId(): string {\n return this.effectOptions.id ?? DEFAULT_EFFECT_LAYER_ID;\n }\n\n private removeEffectLayer(): void {\n const id = this.effectLayerId();\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = undefined;\n }\n\n /** Reconcile the effect state with the map: install, update or remove. */\n private applyRouteEffect(): void {\n const id = this.effectLayerId();\n if (this.effectName === null || this.effectGeometry === undefined) {\n this.removeEffectLayer();\n return;\n }\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.applyRouteEffect());\n return;\n }\n if (this.effectLayer && this.map.getLayer(id)) {\n this.effectLayer.setGeometry(this.effectGeometry);\n return;\n }\n if (this.map.getLayer(id)) this.map.removeLayer(id);\n this.effectLayer = createRouteEffect(this.effectName, this.effectGeometry, {\n ...this.effectOptions,\n id,\n });\n this.map.addLayer(this.effectLayer);\n }\n\n /**\n * Toggle 3D building extrusions at runtime — the live equivalent of\n * compiling the style with `buildings_3d: true` (see `Theme`): adds or\n * removes the `building-3d` fill-extrusion layer and hands the flat\n * `building` footprint layer off at zoom 15. The extrusion takes its\n * colour from the current `building` fill, so it follows the theme.\n * Idempotent; safe to call before the style has loaded (it applies on\n * load). Requires the MapMap skeleton's `building` layer — on a custom\n * style without one this throws rather than guessing.\n *\n * Mobile note: leave 3D off in native navigation views for now\n * (maplibre-native#4107 — fill-extrusion memory at street zooms).\n */\n setBuildings3d(enabled: boolean): void {\n if (!this.map.isStyleLoaded()) {\n this.map.once(\"load\", () => this.setBuildings3d(enabled));\n return;\n }\n if (enabled === (this.map.getLayer(\"building-3d\") !== undefined)) return;\n const building = this.map.getLayer(\"building\");\n if (!building) {\n throw new Error(\n 'setBuildings3d needs the MapMap skeleton \"building\" layer; ' +\n \"the current style does not have one\",\n );\n }\n const minzoom = building.minzoom ?? 13;\n if (enabled) {\n const colour =\n this.map.getPaintProperty(\"building\", \"fill-color\") ?? \"#e2ddd4\";\n this.map.addLayer(\n buildings3dLayer(colour) as unknown as LayerSpecification,\n buildings3dBeforeId(this.map),\n );\n this.map.setLayerZoomRange(\"building\", minzoom, BUILDINGS_3D_MINZOOM);\n } else {\n this.map.removeLayer(\"building-3d\");\n // 24 is the style-spec default maxzoom, i.e. \"uncapped\".\n this.map.setLayerZoomRange(\"building\", minzoom, 24);\n }\n }\n\n /** Resolves once the style and first tiles are loaded. */\n whenReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.map.loaded()) {\n resolve();\n return;\n }\n this.map.once(\"load\", () => resolve());\n });\n }\n\n /** Remove the map and release its WebGL context. */\n destroy(): void {\n this.map.remove();\n }\n}\n\n/** Functional alias for {@link MapMapMap}, mirroring the Mapbox `new Map` feel. */\nexport function createMap(options: MapMapOptions): MapMapMap {\n return new MapMapMap(options);\n}\n\n/**\n * Where the runtime `building-3d` layer goes: the same place the compiler\n * puts it — directly above the base map (after `boundary`), below extras\n * and labels. On a custom style without the skeleton's `boundary` layer,\n * fall back to just below the first symbol layer; `undefined` (append on\n * top) only if there are no symbol layers either.\n */\nfunction buildings3dBeforeId(map: MlMap): string | undefined {\n const layers = map.getStyle().layers ?? [];\n const boundary = layers.findIndex((l) => l.id === \"boundary\");\n if (boundary >= 0) return layers[boundary + 1]?.id;\n return layers.find((l) => l.type === \"symbol\")?.id;\n}\n\n/**\n * The MapMap Studio Theme document behind a `style` option, if that is what\n * it is. An object without a `version` field is a Theme; a full MapLibre\n * StyleSpecification always carries `version: 8`.\n */\nfunction themeOf(style: MapMapOptions[\"style\"]): Theme | undefined {\n if (typeof style === \"object\" && style !== null && !(\"version\" in style)) {\n return style as Theme;\n }\n return undefined;\n}\n\nfunction resolveStyle(\n style: MapMapOptions[\"style\"],\n territoryTilesUrl: string | undefined,\n): StyleSpecification | string {\n if (style === undefined || style === \"light\" || style === \"dark\") {\n return buildStyle({\n theme: style ?? \"light\",\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n const theme = themeOf(style);\n if (theme) {\n return buildStyle({\n theme,\n ...(territoryTilesUrl ? { territoryTilesUrl } : {}),\n });\n }\n return style as StyleSpecification | string;\n}\n","/**\n * Coordinate helpers - pure, browser-free logic.\n *\n * The gateway speaks the OSRM HTTP API: coordinates are `lon,lat` pairs\n * separated by `;`. MapLibre and GeoJSON use `[lng, lat]` order, so the one\n * job here is to normalise the three accepted input shapes into that wire\n * format without ever swapping the axes by accident.\n */\nimport type { LngLatLike } from \"./types.js\";\n\n/** Normalise any accepted shape to a `[lng, lat]` tuple. */\nexport function toLngLat(point: LngLatLike): [number, number] {\n if (Array.isArray(point)) {\n const [lng, lat] = point;\n assertFinite(lng, lat);\n return [lng, lat];\n }\n const lng = \"lng\" in point ? point.lng : point.lon;\n const lat = point.lat;\n assertFinite(lng, lat);\n return [lng, lat];\n}\n\n/** Format one point as an OSRM `lon,lat` coordinate. */\nexport function formatCoord(point: LngLatLike): string {\n const [lng, lat] = toLngLat(point);\n return `${lng},${lat}`;\n}\n\n/**\n * Format an ordered list of points as an OSRM coordinate path\n * (`lon,lat;lon,lat;…`). At least two points are required, matching the\n * gateway, which rejects single-coordinate requests.\n */\nexport function formatCoords(points: LngLatLike[]): string {\n if (points.length < 2) {\n throw new Error(\"at least two coordinates are required for a route\");\n }\n return points.map(formatCoord).join(\";\");\n}\n\nfunction assertFinite(lng: number, lat: number): void {\n if (!Number.isFinite(lng) || !Number.isFinite(lat)) {\n throw new Error(`invalid coordinate: lng=${lng}, lat=${lat}`);\n }\n if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {\n throw new Error(\n `coordinate out of range: lng=${lng} (±180), lat=${lat} (±90) - check lng/lat order`,\n );\n }\n}\n","/**\n * OSRM request assembly and response parsing - pure, browser-free logic.\n *\n * The MapMap gateway exposes `GET /route/v1/{profile}/{coordinates}` speaking\n * the OSRM HTTP API v1, with truck vendor extensions (`height`, `width`,\n * `length`, `weight`, `hazmat`, `tunnel_code`). We always request\n * `geometries=geojson` so the route line arrives as a GeoJSON LineString we\n * can hand straight to a MapLibre source.\n */\nimport { formatCoords } from \"./coords.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteGeometry,\n RouteProfile,\n TruckParams,\n} from \"./types.js\";\n\n/** Guidance-related query options. */\nexport interface GuidanceQuery {\n voice?: boolean;\n banner?: boolean;\n language?: string;\n}\n\n/** Build the OSRM query string (without the leading `?`) for a request. */\nexport function buildRouteQuery(truck?: TruckParams, guidance?: GuidanceQuery): string {\n const params = new URLSearchParams({\n geometries: \"geojson\",\n overview: \"full\",\n steps: \"true\",\n });\n if (guidance?.voice) params.set(\"voice_instructions\", \"true\");\n if (guidance?.banner) params.set(\"banner_instructions\", \"true\");\n if (guidance?.language) params.set(\"language\", guidance.language);\n if (truck) {\n if (truck.heightM != null) params.set(\"height\", String(truck.heightM));\n if (truck.widthM != null) params.set(\"width\", String(truck.widthM));\n if (truck.lengthM != null) params.set(\"length\", String(truck.lengthM));\n if (truck.weightT != null) params.set(\"weight\", String(truck.weightT));\n if (truck.hazmat != null) params.set(\"hazmat\", String(truck.hazmat));\n // URLSearchParams encodes the slash in codes like \"B/D\" for us.\n if (truck.tunnelCode != null) params.set(\"tunnel_code\", truck.tunnelCode);\n }\n return params.toString();\n}\n\n/**\n * Build the full OSRM route URL. `baseUrl` is the gateway origin (trailing\n * slashes are trimmed); `points` is the ordered coordinate path.\n */\nexport function buildRouteUrl(\n baseUrl: string,\n profile: RouteProfile,\n points: LngLatLike[],\n truck?: TruckParams,\n guidance?: GuidanceQuery,\n): string {\n const origin = baseUrl.replace(/\\/+$/, \"\");\n const coords = formatCoords(points);\n const query = buildRouteQuery(truck, guidance);\n return `${origin}/route/v1/${encodeURIComponent(profile)}/${coords}?${query}`;\n}\n\n/**\n * Parse an OSRM route response into a {@link ParsedRoute}. Throws with the\n * OSRM `code`/`message` when the response is not `Ok` or carries no route.\n */\nexport function parseOsrmRoute(body: unknown): ParsedRoute {\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"OSRM response was not an object\");\n }\n const obj = body as Record<string, unknown>;\n const code = obj[\"code\"];\n if (code !== \"Ok\") {\n const message = typeof obj[\"message\"] === \"string\" ? obj[\"message\"] : \"\";\n throw new Error(\n `OSRM routing failed: ${String(code)}${message ? ` - ${message}` : \"\"}`,\n );\n }\n\n const routes = obj[\"routes\"];\n if (!Array.isArray(routes) || routes.length === 0) {\n throw new Error(\"OSRM response contained no routes\");\n }\n const route = routes[0] as Record<string, unknown>;\n\n const geometry = parseGeometry(route[\"geometry\"]);\n const distanceM = numberOr(route[\"distance\"], 0);\n const durationS = numberOr(route[\"duration\"], 0);\n\n return { distanceM, durationS, geometry, raw: route };\n}\n\nfunction parseGeometry(geometry: unknown): RouteGeometry {\n if (\n typeof geometry !== \"object\" ||\n geometry === null ||\n (geometry as { type?: unknown }).type !== \"LineString\"\n ) {\n throw new Error(\n \"route geometry was not GeoJSON - request geometries=geojson\",\n );\n }\n const coordinates = (geometry as { coordinates?: unknown }).coordinates;\n if (!Array.isArray(coordinates)) {\n throw new Error(\"route geometry had no coordinates\");\n }\n const positions: [number, number][] = coordinates.map((pos, i) => {\n if (\n !Array.isArray(pos) ||\n typeof pos[0] !== \"number\" ||\n typeof pos[1] !== \"number\"\n ) {\n throw new Error(`route geometry position ${i} is not [lng, lat]`);\n }\n return [pos[0], pos[1]];\n });\n return { type: \"LineString\", coordinates: positions };\n}\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n","/**\n * RouteLayer - fetch an OSRM route from the MapMap gateway and draw it.\n *\n * The route request/parse logic lives in the pure `osrm` module; this class\n * owns the network call and the MapLibre source/layers (a signal-blue line\n * with a darker casing, matching the brand).\n */\nimport type {\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n} from \"maplibre-gl\";\nimport { buildRouteUrl, parseOsrmRoute } from \"./osrm.js\";\nimport type {\n LngLatLike,\n ParsedRoute,\n RouteOptions,\n} from \"./types.js\";\nimport { MapMapMap } from \"./map.js\";\nimport type { NavRouteDesign } from \"./nav-design.js\";\n\n/** MapMap brand signal blue (see website `--signal`). */\nexport const SIGNAL_BLUE = \"#3a86ff\";\nconst CASING_COLOR = \"#1f438a\";\n\nexport interface RouteLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-route\"`. */\n id?: string;\n /**\n * Studio route design (`extra.nav` `route` block). Defaults to the map's\n * `navDesign.route` when given a `MapMapMap` whose theme carried one;\n * without a design the layer keeps its built-in signal-blue look.\n */\n design?: NavRouteDesign;\n}\n\n/** Draws MapMap routes on a MapLibre map. */\nexport class RouteLayer {\n private readonly map: MlMap;\n /** The owning MapMapMap, when built from one - fed each drawn route so\n * an armed route effect (`setRouteEffect`) attaches automatically. */\n private readonly owner: MapMapMap | undefined;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly casingLayerId: string;\n private readonly lineLayerId: string;\n private readonly design: NavRouteDesign | undefined;\n private lastRoute: ParsedRoute | undefined;\n\n constructor(map: MapMapMap | MlMap, options: RouteLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.owner = map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n this.design = options.design ?? map.navDesign?.route;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\"RouteLayer needs a baseUrl when given a raw MapLibre map\");\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.design = options.design;\n }\n const id = options.id ?? \"mapmap-route\";\n this.sourceId = `${id}-src`;\n this.casingLayerId = `${id}-casing`;\n this.lineLayerId = `${id}-line`;\n // MapLibre wipes runtime sources/layers on every setStyle (e.g. a\n // light/dark theme swap), so re-install the route after each style\n // load — the same pattern the playground uses. This also completes a\n // draw() that arrived before the initial style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastRoute) this.install(this.lastRoute);\n };\n\n /**\n * Route from `from` to `to` (with optional intermediate `via` points passed\n * through `options` is not supported here - pass a coordinate list to\n * {@link routePath} for that), draw the line, and return the parsed route.\n */\n async route(\n from: LngLatLike,\n to: LngLatLike,\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n return this.routePath([from, to], options);\n }\n\n /** Route through an ordered list of coordinates and draw the result. */\n async routePath(\n points: LngLatLike[],\n options: RouteOptions = {},\n ): Promise<ParsedRoute> {\n const url = buildRouteUrl(\n this.baseUrl,\n options.profile ?? \"driving\",\n points,\n options.truck,\n { voice: options.voice, banner: options.banner, language: options.language },\n );\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(url, { headers });\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n const obj =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n // Only OSRM-shaped error bodies (with a \"code\") belong to the routing\n // engine; anything else (e.g. the gateway's RFC 9457 problem+json for\n // 401/429) is reported with its status and title/detail instead of\n // being misattributed as an OSRM failure.\n if (typeof obj?.[\"code\"] !== \"string\") {\n const context = [obj?.[\"title\"], obj?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `route request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n }\n const parsed = parseOsrmRoute(body);\n this.draw(parsed);\n return parsed;\n }\n\n /** The most recently drawn route, if any. */\n get current(): ParsedRoute | undefined {\n return this.lastRoute;\n }\n\n /**\n * Draw (or update) a parsed route's line on the map. Safe to call before\n * the style has loaded: the route is stored and installed on the next\n * `style.load` instead of throwing MapLibre's \"Style is not done loading\".\n */\n draw(route: ParsedRoute): void {\n this.lastRoute = route;\n if (this.map.isStyleLoaded()) this.install(route);\n // else: installed by handleStyleLoad.\n // Attach any armed route effect (map.setRouteEffect) to this line -\n // after install, so the effect's custom layer lands above the line.\n this.owner?.setRouteEffectGeometry(route.geometry);\n }\n\n /** Add-or-update the source and layers for a route on the current style. */\n private install(route: ParsedRoute): void {\n const data = {\n type: \"Feature\" as const,\n properties: {},\n geometry: route.geometry,\n };\n\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, { type: \"geojson\", data });\n }\n\n if (this.map.getLayer(this.casingLayerId) && this.map.getLayer(this.lineLayerId)) {\n return;\n }\n\n // With a Studio design the paints follow the Studio preview exactly\n // (constant width, casing = width + 4, shared opacity — see\n // syncNavOverlay in the Studio client); without one they keep the\n // built-in zoom-interpolated signal-blue look, unchanged.\n const casing: LineLayerSpecification = {\n id: this.casingLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.casingColor,\n \"line-width\": this.design.width + 4,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": CASING_COLOR,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 6, 16, 12],\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n layout: { \"line-cap\": \"round\", \"line-join\": \"round\" },\n paint: this.design\n ? {\n \"line-color\": this.design.color,\n \"line-width\": this.design.width,\n \"line-opacity\": this.design.opacity,\n }\n : {\n \"line-color\": SIGNAL_BLUE,\n \"line-width\": [\"interpolate\", [\"linear\"], [\"zoom\"], 8, 3, 16, 8],\n },\n };\n\n if (!this.map.getLayer(this.casingLayerId)) this.map.addLayer(casing);\n if (!this.map.getLayer(this.lineLayerId)) this.map.addLayer(line);\n }\n\n /** Remove the route's layers and source from the map. */\n clear(): void {\n for (const layerId of [this.lineLayerId, this.casingLayerId]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastRoute = undefined;\n // The route is gone; take any route effect with it.\n this.owner?.setRouteEffectGeometry(null);\n }\n\n /**\n * Remove the route and detach the layer's `style.load` listener. Call\n * when disposing of the layer (the map itself is left untouched).\n */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * PositionPuck - the current-position marker, styled by a Studio design.\n *\n * A MapLibre `Marker`-based puck: a coloured dot with an optional heading\n * arrow, or a custom image (`https:`/`data:` URI, data payloads capped at\n * 64 KB - the same cap Studio enforces on upload) that replaces both and\n * falls back to the built-in dot if it fails to load. The marker survives\n * `setStyle` on its own (markers are DOM overlays, not style layers), so\n * no `style.load` re-install is needed.\n *\n * LOCKSTEP: the element structure and styling mirror `createPuckElement` /\n * `stylePuckElement` in the Studio client\n * (`website/app/studio/StudioClient.tsx`), so a theme's puck renders here\n * exactly as Studio previews it.\n *\n * Like `MapMapMap` (see map.ts), this module imports the SDK's bundled\n * maplibre-gl for the `Marker` constructor - a purely structural typing\n * (the `LogoControl` pattern) is not possible because a Marker must be\n * constructed, not just duck-typed.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type { Map as MlMap, Marker } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { defaultNavDesign, type NavPuckDesign } from \"./nav-design.js\";\n\n/** Maximum accepted `data:` puck-image payload (matches Studio's upload cap). */\nexport const MAX_PUCK_IMAGE_BYTES = 64 * 1024;\n\n/**\n * Approximate decoded byte size of a `data:` URI payload (base64 payloads\n * decode to 3/4 of their character count; other payloads are counted as-is,\n * an upper bound for percent-encoded text).\n */\nfunction dataUriBytes(uri: string): number {\n const comma = uri.indexOf(\",\");\n const payload = comma === -1 ? \"\" : uri.slice(comma + 1);\n const meta = comma === -1 ? uri : uri.slice(0, comma);\n return /;base64$/i.test(meta) || /;base64;/i.test(meta)\n ? Math.floor((payload.length * 3) / 4)\n : payload.length;\n}\n\n/** The design's image URL, or `undefined` when unusable (built-in puck). */\nfunction effectiveImageUrl(design: NavPuckDesign): string | undefined {\n const url = design.imageUrl?.trim();\n if (!url) return undefined;\n if (/^data:/i.test(url) && dataUriBytes(url) > MAX_PUCK_IMAGE_BYTES) {\n return undefined;\n }\n return url;\n}\n\n/** A current-position puck marker for MapMap maps. */\nexport class PositionPuck {\n /** The puck's root DOM element (the Marker element). */\n readonly element: HTMLElement;\n private readonly map: MlMap;\n private readonly marker: Marker;\n private readonly design: NavPuckDesign;\n private added = false;\n\n /**\n * Creates the puck (not yet on the map - it appears on the first\n * {@link setLocation}). The design defaults to the map's\n * `navDesign.puck` when given a `MapMapMap` whose theme carried an\n * `extra.nav` block, then to the built-in blue puck.\n */\n constructor(map: MapMapMap | MlMap, design?: NavPuckDesign) {\n this.map = map instanceof MapMapMap ? map.map : map;\n this.design =\n design ??\n (map instanceof MapMapMap ? map.navDesign?.puck : undefined) ??\n defaultNavDesign().puck;\n this.element = createPuckElement();\n stylePuckElement(this.element, this.design);\n // Map-aligned rotation/pitch: the puck lies flat on the map and its\n // heading rotates with the camera bearing, as in the Studio preview.\n this.marker = new maplibregl.Marker({\n element: this.element,\n rotationAlignment: \"map\",\n pitchAlignment: \"map\",\n });\n }\n\n /**\n * Moves the puck (adding it to the map on the first call). `headingDeg`\n * rotates the whole element - arrow or custom image - clockwise from\n * north; omit it to keep the previous heading.\n */\n setLocation(location: { lat: number; lon: number }, headingDeg?: number): void {\n this.marker.setLngLat([location.lon, location.lat]);\n if (headingDeg !== undefined) this.marker.setRotation(headingDeg);\n if (!this.added) {\n this.marker.addTo(this.map);\n this.added = true;\n }\n }\n\n /** Removes the puck from the map. `setLocation` re-adds it. */\n remove(): void {\n this.marker.remove();\n this.added = false;\n }\n}\n\n/**\n * The puck element: a dot plus an optional heading-arrow triangle, and a\n * (hidden by default) custom-image slot that replaces both when the design\n * carries an `imageUrl`. LOCKSTEP with Studio's `createPuckElement`.\n */\nfunction createPuckElement(): HTMLElement {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"PositionPuck requires a DOM environment\");\n const el = doc.createElement(\"div\");\n el.className = \"mapmap-puck\";\n el.style.position = \"relative\";\n const arrow = doc.createElement(\"div\");\n arrow.dataset[\"part\"] = \"arrow\";\n const dot = doc.createElement(\"div\");\n dot.dataset[\"part\"] = \"dot\";\n const img = doc.createElement(\"img\");\n img.dataset[\"part\"] = \"image\";\n img.alt = \"\";\n img.draggable = false;\n img.style.display = \"none\";\n el.append(arrow, dot, img);\n return el;\n}\n\n/**\n * Applies a puck design to the element. LOCKSTEP with Studio's\n * `stylePuckElement`: same sizes, colours, shadows and image fallback (a\n * URL that fails to load is remembered on the element and the built-in\n * puck shows instead).\n */\nfunction stylePuckElement(el: HTMLElement, puck: NavPuckDesign): void {\n const dot = el.querySelector<HTMLElement>(\"[data-part='dot']\");\n const arrow = el.querySelector<HTMLElement>(\"[data-part='arrow']\");\n const img = el.querySelector<HTMLImageElement>(\"[data-part='image']\");\n if (!dot || !arrow || !img) return;\n const s = puck.size;\n el.style.width = `${s}px`;\n el.style.height = `${s}px`;\n const url = effectiveImageUrl(puck) ?? \"\";\n if (url !== \"\" && el.dataset[\"imageFailed\"] !== url) {\n if (img.getAttribute(\"src\") !== url) {\n img.onerror = () => {\n el.dataset[\"imageFailed\"] = url;\n img.removeAttribute(\"src\");\n stylePuckElement(el, puck);\n };\n img.src = url;\n }\n img.style.cssText =\n `display:block;position:absolute;inset:0;width:${s}px;height:${s}px;` +\n \"object-fit:contain;filter:drop-shadow(0 1px 4px rgba(0,0,0,0.5))\";\n dot.style.cssText = \"display:none\";\n arrow.style.cssText = \"display:none\";\n return;\n }\n img.onerror = null;\n if (img.getAttribute(\"src\") !== null) img.removeAttribute(\"src\");\n img.style.cssText = \"display:none\";\n dot.style.cssText =\n `position:absolute;inset:0;border-radius:50%;background:${puck.color};` +\n \"border:2px solid #ffffff;box-shadow:0 1px 6px rgba(0,0,0,0.45)\";\n arrow.style.cssText = puck.headingArrow\n ? `position:absolute;left:50%;top:${(-s * 0.55).toFixed(1)}px;transform:translateX(-50%);` +\n `width:0;height:0;border-left:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-right:${(s * 0.35).toFixed(1)}px solid transparent;` +\n `border-bottom:${(s * 0.6).toFixed(1)}px solid ${puck.color}`\n : \"display:none\";\n}\n","/**\n * PlacesLayer - drop your own places (store locations, depots, POIs) onto a\n * MapMap map: the store-finder use case.\n *\n * A GeoJSON source plus MapLibre layers, following the RouteLayer pattern:\n * native clustering (`cluster: true` on the source) with count badges,\n * click-to-expand clusters, a typed `onPlaceClick` callback and an optional\n * built-in popup, plus pure `nearest()` (haversine) and gateway-backed\n * `nearestByDriveTime()` (`POST /matrix`) helpers for \"which branch is\n * closest?\".\n *\n * Like RouteLayer, the layer survives `setStyle` (light/dark theme swaps):\n * places are re-installed on every `style.load`.\n */\nimport maplibregl from \"maplibre-gl\";\nimport type {\n CircleLayerSpecification,\n ExpressionSpecification,\n GeoJSONSource,\n MapLayerMouseEvent,\n Map as MlMap,\n Popup,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\n\n/** Mean Earth radius in metres (IUGG), as used by turf and PostGIS. */\nconst EARTH_RADIUS_M = 6371008.8;\n/** Font stack for cluster-count badges; ships with the MapMap default styles. */\nconst CLUSTER_TEXT_FONT = \"Noto Sans Regular\";\n\n/** One place to show on the map - a store, depot, branch, POI. */\nexport interface Place {\n /** Stable unique id, e.g. your store number. */\n id: string;\n /** Display name. */\n name: string;\n /** Latitude, degrees. */\n lat: number;\n /** Longitude, degrees. */\n lon: number;\n /**\n * Arbitrary extra data (opening hours, phone, …). Every key is copied\n * verbatim onto the top level of the GeoJSON feature's `properties`,\n * alongside the reserved `id`, `name` and `__mapmapIndex` keys (which win\n * on collision) - so scalar values are directly addressable from a\n * data-driven `color` expression, e.g. `[\"get\", \"category\"]`. MapLibre\n * JSON-stringifies nested objects/arrays at render time, so keep anything\n * you want to style on as a top-level string/number/boolean. The whole\n * object also comes back on the place handed to `onPlaceClick` / `popup`.\n */\n properties?: Record<string, unknown>;\n}\n\n/** A GeoJSON Point feature, as accepted in a {@link PlacesFeatureCollection}. */\nexport interface PlacePointFeature {\n type: \"Feature\";\n id?: string | number;\n geometry: { type: \"Point\"; coordinates: number[] };\n properties?: Record<string, unknown> | null;\n}\n\n/**\n * A plain GeoJSON FeatureCollection of Points, accepted anywhere a `Place[]`\n * is (structurally compatible with `@types/geojson`'s\n * `FeatureCollection<Point>`). See {@link placesFromGeoJSON} for how ids and\n * names are derived.\n */\nexport interface PlacesFeatureCollection {\n type: \"FeatureCollection\";\n features: PlacePointFeature[];\n}\n\n/** Either input shape for {@link PlacesLayer} / `setPlaces`. */\nexport type PlacesInput = Place[] | PlacesFeatureCollection;\n\n/** A place with its straight-line distance attached (see `nearest`). */\nexport type PlaceWithDistance = Place & {\n /** Straight-line (haversine) distance from the origin, metres. */\n distanceM: number;\n};\n\n/** A place with gateway drive time attached (see `nearestByDriveTime`). */\nexport type PlaceWithDriveTime = Place & {\n /** Drive time from the origin, seconds. */\n durationS: number;\n /** Driven distance from the origin, metres (`null` when not returned). */\n distanceM: number | null;\n};\n\n/** A custom pin image for unclustered places. */\nexport interface PlacesIcon {\n /** Image URL (any format `Map#loadImage` accepts, e.g. PNG). */\n url: string;\n /** MapLibre `icon-size` scale factor. Defaults to `1`. */\n size?: number;\n}\n\n/** Options for {@link PlacesLayer.nearestByDriveTime}. */\nexport interface NearestByDriveTimeOptions {\n /** How many places to return. Defaults to `1`. */\n n?: number;\n /**\n * Gateway costing model, e.g. `\"auto\"` (default) or `\"truck\"` (Premium\n * price class - see `POST /matrix` in the API docs).\n */\n costing?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ truck: { height: 4.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface PlacesLayerOptions {\n /** Initial places. Also settable later via {@link PlacesLayer.setPlaces}. */\n places?: PlacesInput;\n /** Cluster nearby places into count badges. Defaults to `true`. */\n cluster?: boolean;\n /** Cluster radius in pixels. Defaults to MapLibre's `50`. */\n clusterRadius?: number;\n /** Max zoom to cluster at. Defaults to MapLibre's `14`. */\n clusterMaxZoom?: number;\n /**\n * Pin colour: a CSS colour string, or a MapLibre expression evaluated\n * against each feature's `properties` for per-category pins, e.g.\n * `[\"match\", [\"get\", \"category\"], \"food\", \"#e63946\", \"#3a86ff\"]` (see\n * {@link Place.properties} for what an expression can `get`). Defaults to\n * MapMap signal blue (`#3a86ff`). Only styles the default circle pins -\n * ignored with a custom `icon`. A cluster mixes categories, so an\n * expression never applies to clusters: they use `clusterColor`.\n */\n color?: string | ExpressionSpecification;\n /**\n * Cluster circle colour. Defaults to `color` when that is a plain string,\n * else to MapMap signal blue (a cluster mixes categories, so a\n * data-driven `color` expression cannot apply to it).\n */\n clusterColor?: string;\n /**\n * Custom pin image for unclustered places (a symbol layer instead of the\n * default circle). If the image fails to load, the circle look is used.\n */\n icon?: PlacesIcon;\n /**\n * Fit the map to the places the first time they are set. Defaults to\n * `false` (the map view is left alone).\n */\n fitBounds?: boolean;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-places\"`. */\n id?: string;\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Called when an individual (unclustered) place is clicked. */\n onPlaceClick?: (place: Place, lngLat: { lng: number; lat: number }) => void;\n /**\n * Built-in popup: return HTML (a string is set with `setHTML`, an element\n * with `setDOMContent`) and a `maplibregl.Popup` opens at the place on\n * click. Omit for no popup.\n */\n popup?: (place: Place) => string | HTMLElement;\n}\n\n/** The generated MapLibre source/layer ids (see {@link PlacesLayer.ids}). */\nexport interface PlacesLayerIds {\n /** The GeoJSON source id. */\n source: string;\n /** The unclustered-points layer id (circle, or symbol with `icon`). */\n points: string;\n /** The cluster circles layer id (only installed with `cluster: true`). */\n clusters: string;\n /** The cluster count badge layer id (only installed with `cluster: true`). */\n clusterCounts: string;\n}\n\n/** Options for {@link PlacesLayer.select}. */\nexport interface PlacesSelectOptions {\n /** Open the layer's configured `popup` at the place. Defaults to `true`. */\n popup?: boolean;\n /** Ease the camera to the place. Defaults to `true`. */\n flyTo?: boolean;\n /** Zoom for the camera move (with `flyTo`). Keeps the current zoom if omitted. */\n zoom?: number;\n}\n\n/**\n * Normalise a GeoJSON FeatureCollection of Points to `Place[]`. The id comes\n * from `feature.id`, then `properties.id`, then the feature index; the name\n * from `properties.name` (else `\"\"`). Non-Point features are skipped.\n */\nexport function placesFromGeoJSON(\n collection: PlacesFeatureCollection,\n): Place[] {\n const places: Place[] = [];\n collection.features.forEach((feature, index) => {\n if (feature.geometry?.type !== \"Point\") return;\n const [lon, lat] = feature.geometry.coordinates;\n if (typeof lon !== \"number\" || typeof lat !== \"number\") {\n throw new Error(`place feature ${index} has no [lon, lat] coordinates`);\n }\n const props = feature.properties ?? {};\n const rawId = feature.id ?? props[\"id\"];\n const place: Place = {\n id:\n typeof rawId === \"string\" || typeof rawId === \"number\"\n ? String(rawId)\n : String(index),\n name: typeof props[\"name\"] === \"string\" ? props[\"name\"] : \"\",\n lat,\n lon,\n };\n if (feature.properties) place.properties = feature.properties;\n places.push(place);\n });\n return places;\n}\n\n/** Straight-line (haversine) distance between two points, metres. */\nexport function haversineDistanceM(\n a: { lat: number; lon: number },\n b: { lat: number; lon: number },\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b.lat - a.lat);\n const dLon = rad(b.lon - a.lon);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/** The GeoJSON built for the source; one Point feature per place. */\ninterface PlacesSourceData {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: \"Point\"; coordinates: [number, number] };\n properties: Record<string, unknown>;\n }[];\n}\n\n/** Draws customer places on a MapLibre map, with clustering and popups. */\nexport class PlacesLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string | undefined;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly clustersLayerId: string;\n private readonly clusterCountLayerId: string;\n private readonly pointsLayerId: string;\n private readonly iconImageId: string;\n private readonly cluster: boolean;\n private readonly clusterRadius: number | undefined;\n private readonly clusterMaxZoom: number | undefined;\n private readonly color: string | ExpressionSpecification;\n private readonly clusterColor: string;\n private readonly icon: PlacesIcon | undefined;\n private readonly wantFitBounds: boolean;\n private readonly onPlaceClick:\n | ((place: Place, lngLat: { lng: number; lat: number }) => void)\n | undefined;\n private readonly popupFn:\n | ((place: Place) => string | HTMLElement)\n | undefined;\n private places: Place[] = [];\n private data: PlacesSourceData | undefined;\n private popup: Popup | undefined;\n private fitted = false;\n private destroyed = false;\n\n constructor(map: MapMapMap | MlMap, options: PlacesLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n this.baseUrl = options.baseUrl?.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-places\";\n this.sourceId = `${id}-src`;\n this.clustersLayerId = `${id}-clusters`;\n this.clusterCountLayerId = `${id}-cluster-count`;\n this.pointsLayerId = `${id}-points`;\n this.iconImageId = `${id}-icon`;\n this.cluster = options.cluster ?? true;\n this.clusterRadius = options.clusterRadius;\n this.clusterMaxZoom = options.clusterMaxZoom;\n this.color = options.color ?? SIGNAL_BLUE;\n this.clusterColor =\n options.clusterColor ??\n (typeof this.color === \"string\" ? this.color : SIGNAL_BLUE);\n this.icon = options.icon;\n this.wantFitBounds = options.fitBounds ?? false;\n this.onPlaceClick = options.onPlaceClick;\n this.popupFn = options.popup;\n\n // Same lifecycle as RouteLayer: runtime sources/layers are wiped on\n // every setStyle (theme swap), so re-install on each style.load - which\n // also completes a setPlaces that arrived before the style had loaded.\n this.map.on(\"style.load\", this.handleStyleLoad);\n // Delegated layer events survive layer re-installation (they are bound\n // to the layer id, not the layer object), so bind them once here.\n this.map.on(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.on(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.on(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.on(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.on(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n\n if (options.places) this.setPlaces(options.places);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.data) this.install(this.data);\n };\n\n private readonly handleMouseEnter = (): void => {\n this.map.getCanvas().style.cursor = \"pointer\";\n };\n\n private readonly handleMouseLeave = (): void => {\n this.map.getCanvas().style.cursor = \"\";\n };\n\n private readonly handlePlaceClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const index: unknown = feature.properties?.[\"__mapmapIndex\"];\n if (typeof index !== \"number\") return;\n const place = this.places[index];\n if (!place) return;\n this.onPlaceClick?.(place, { lng: e.lngLat.lng, lat: e.lngLat.lat });\n if (this.popupFn) this.openPopup(place);\n };\n\n private readonly handleClusterClick = (e: MapLayerMouseEvent): void => {\n const feature = e.features?.[0];\n if (!feature) return;\n const clusterId: unknown = feature.properties?.[\"cluster_id\"];\n if (typeof clusterId !== \"number\") return;\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (!source) return;\n const geometry = feature.geometry;\n if (geometry.type !== \"Point\") return;\n const [lng, lat] = geometry.coordinates;\n if (typeof lng !== \"number\" || typeof lat !== \"number\") return;\n void source\n .getClusterExpansionZoom(clusterId)\n .then((zoom) => {\n if (!this.destroyed) this.map.easeTo({ center: [lng, lat], zoom });\n })\n .catch(() => {\n /* cluster no longer in the source (data changed mid-flight) */\n });\n };\n\n /**\n * Replace the layer's places - a `Place[]` or a GeoJSON FeatureCollection\n * of Points. Never silently drops an update: once the source exists the\n * data is applied immediately, even while `isStyleLoaded()` is transiently\n * `false` mid-render (search-as-you-type just works); calls made before\n * the source has first been installed are stashed - the latest one wins -\n * and installed on the next `style.load`. With `fitBounds: true` the\n * first non-empty set also fits the map view.\n */\n setPlaces(places: PlacesInput): void {\n this.places = Array.isArray(places) ? places : placesFromGeoJSON(places);\n this.data = {\n type: \"FeatureCollection\",\n features: this.places.map((place, index) => ({\n type: \"Feature\",\n geometry: { type: \"Point\", coordinates: [place.lon, place.lat] },\n properties: {\n ...place.properties,\n id: place.id,\n name: place.name,\n __mapmapIndex: index,\n },\n })),\n };\n if (this.wantFitBounds && !this.fitted && this.places.length > 0) {\n this.fitted = true;\n this.map.fitBounds(boundsOf(this.places), { padding: 48, maxZoom: 15 });\n }\n const source = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (source) {\n // setData on an existing source is safe even while isStyleLoaded()\n // is transiently false (tiles/cluster work in flight) - never drop\n // an update once the source is installed.\n source.setData(this.data);\n } else if (this.map.isStyleLoaded()) {\n this.install(this.data);\n }\n // else: kept in this.data (latest call wins) until handleStyleLoad.\n }\n\n /** The layer's current places (normalised to `Place[]`). */\n get current(): Place[] {\n return this.places;\n }\n\n /**\n * The generated MapLibre source/layer ids - public API for escape-hatch\n * styling (`map.setPaintProperty`, `queryRenderedFeatures`, …) beyond the\n * layer's options. Stable for the layer's lifetime, derived from the `id`\n * option (default `\"mapmap-places\"`). The cluster ids are only installed\n * on the map with `cluster: true` (the default), and `points` is a circle\n * layer by default or a symbol layer once a custom `icon` has loaded.\n */\n get ids(): PlacesLayerIds {\n return {\n source: this.sourceId,\n points: this.pointsLayerId,\n clusters: this.clustersLayerId,\n clusterCounts: this.clusterCountLayerId,\n };\n }\n\n /**\n * Programmatically select a place by id - list-to-map sync for a store\n * finder's results list. Opens the layer's configured `popup` at the\n * place (`popup: false` to skip, no-op without a `popup` option) and\n * eases the camera to it (`flyTo: false` to skip; `zoom` to also zoom).\n * Returns the selected place, or `undefined` for an unknown id (in which\n * case nothing happens). Does NOT invoke `onPlaceClick` - a programmatic\n * selection is not a user click.\n */\n select(id: string, options: PlacesSelectOptions = {}): Place | undefined {\n const place = this.places.find((p) => p.id === id);\n if (!place) return undefined;\n if (options.flyTo ?? true) {\n this.map.easeTo({\n center: [place.lon, place.lat],\n ...(options.zoom !== undefined ? { zoom: options.zoom } : {}),\n });\n }\n if (options.popup ?? true) this.openPopup(place);\n return place;\n }\n\n /** Close the popup opened by {@link select} or a place click, if any. */\n deselect(): void {\n this.popup?.remove();\n this.popup = undefined;\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by straight-line\n * (haversine) distance, each with `distanceM` attached. Pure and instant -\n * no network. For road-network answers use {@link nearestByDriveTime}.\n */\n nearest(origin: { lat: number; lon: number }, n = 1): PlaceWithDistance[] {\n return this.places\n .map((place) => ({ ...place, distanceM: haversineDistanceM(origin, place) }))\n .sort((a, b) => a.distanceM - b.distanceM)\n .slice(0, Math.max(0, n));\n }\n\n /**\n * The nearest `n` places (default `1`) to `origin` by drive time, via the\n * gateway's `POST /matrix` (one source, all places as targets). Resolves\n * to places sorted by `durationS` ascending, with the driven `distanceM`\n * attached; unreachable places (`null` duration) are dropped. Needs the\n * gateway `baseUrl`/`apiKey` - picked up from a `MapMapMap` automatically,\n * or pass them as layer options.\n */\n async nearestByDriveTime(\n origin: { lat: number; lon: number },\n options: NearestByDriveTimeOptions = {},\n ): Promise<PlaceWithDriveTime[]> {\n if (!this.baseUrl) {\n throw new Error(\n \"PlacesLayer needs a baseUrl (or a MapMapMap) for nearestByDriveTime\",\n );\n }\n if (this.places.length === 0) return [];\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n const body: Record<string, unknown> = {\n sources: [{ lat: origin.lat, lon: origin.lon }],\n targets: this.places.map((p) => ({ lat: p.lat, lon: p.lon })),\n costing: options.costing ?? \"auto\",\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const response = await fetch(`${this.baseUrl}/matrix`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `matrix request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n const { durations, distances } = matrixRows(payload);\n\n const reachable: PlaceWithDriveTime[] = [];\n this.places.forEach((place, index) => {\n const durationS = durations[index];\n if (typeof durationS !== \"number\") return; // null = unreachable\n const distanceM = distances?.[index];\n reachable.push({\n ...place,\n durationS,\n distanceM: typeof distanceM === \"number\" ? distanceM : null,\n });\n });\n reachable.sort((a, b) => a.durationS - b.durationS);\n return reachable.slice(0, Math.max(0, options.n ?? 1));\n }\n\n /** Add-or-update the source and layers on the current style. */\n private install(data: PlacesSourceData): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(data);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data,\n cluster: this.cluster,\n ...(this.cluster && this.clusterRadius !== undefined\n ? { clusterRadius: this.clusterRadius }\n : {}),\n ...(this.cluster && this.clusterMaxZoom !== undefined\n ? { clusterMaxZoom: this.clusterMaxZoom }\n : {}),\n });\n }\n\n if (this.cluster) this.installClusterLayers();\n this.installPointsLayer();\n }\n\n /** Cluster circles (sized by count) and the count badge on top. */\n private installClusterLayers(): void {\n if (!this.map.getLayer(this.clustersLayerId)) {\n const clusters: CircleLayerSpecification = {\n id: this.clustersLayerId,\n type: \"circle\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n paint: {\n \"circle-color\": this.clusterColor,\n \"circle-opacity\": 0.9,\n \"circle-radius\": [\"step\", [\"get\", \"point_count\"], 16, 25, 20, 100, 26],\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(clusters);\n }\n if (!this.map.getLayer(this.clusterCountLayerId)) {\n const count: SymbolLayerSpecification = {\n id: this.clusterCountLayerId,\n type: \"symbol\",\n source: this.sourceId,\n filter: [\"has\", \"point_count\"],\n layout: {\n \"text-field\": [\"get\", \"point_count_abbreviated\"],\n \"text-font\": [CLUSTER_TEXT_FONT],\n \"text-size\": 12,\n },\n paint: { \"text-color\": \"#ffffff\" },\n };\n this.map.addLayer(count);\n }\n }\n\n /**\n * The unclustered-places layer: a circle pin by default, or a symbol\n * layer once the custom `icon` image has loaded (falling back to the\n * circle look if it fails, like PositionPuck's image fallback).\n */\n private installPointsLayer(): void {\n if (this.map.getLayer(this.pointsLayerId)) return;\n if (!this.icon) {\n this.addCirclePointsLayer();\n return;\n }\n if (this.map.hasImage(this.iconImageId)) {\n this.addIconPointsLayer();\n return;\n }\n void this.map\n .loadImage(this.icon.url)\n .then((image) => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n if (!this.map.hasImage(this.iconImageId)) {\n this.map.addImage(this.iconImageId, image.data);\n }\n this.addIconPointsLayer();\n })\n .catch(() => {\n if (this.destroyed || this.map.getLayer(this.pointsLayerId)) return;\n this.addCirclePointsLayer();\n });\n }\n\n private addCirclePointsLayer(): void {\n const points: CircleLayerSpecification = {\n id: this.pointsLayerId,\n type: \"circle\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n paint: {\n \"circle-color\": this.color,\n \"circle-radius\": 7,\n \"circle-stroke-color\": \"#ffffff\",\n \"circle-stroke-width\": 2,\n },\n };\n this.map.addLayer(points);\n }\n\n private addIconPointsLayer(): void {\n const points: SymbolLayerSpecification = {\n id: this.pointsLayerId,\n type: \"symbol\",\n source: this.sourceId,\n ...(this.cluster ? { filter: [\"!\", [\"has\", \"point_count\"]] } : {}),\n layout: {\n \"icon-image\": this.iconImageId,\n \"icon-size\": this.icon?.size ?? 1,\n \"icon-allow-overlap\": true,\n },\n };\n this.map.addLayer(points);\n }\n\n /** Open the built-in popup for a place, replacing any previous one. */\n private openPopup(place: Place): void {\n if (!this.popupFn) return;\n const content = this.popupFn(place);\n const popup = new maplibregl.Popup({ offset: 12 }).setLngLat([\n place.lon,\n place.lat,\n ]);\n if (typeof content === \"string\") popup.setHTML(content);\n else popup.setDOMContent(content);\n this.popup?.remove();\n this.popup = popup.addTo(this.map);\n }\n\n /** Remove the places' layers, source, image and popup from the map. */\n clear(): void {\n this.popup?.remove();\n this.popup = undefined;\n for (const layerId of [\n this.pointsLayerId,\n this.clusterCountLayerId,\n this.clustersLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n if (this.map.hasImage(this.iconImageId)) {\n this.map.removeImage(this.iconImageId);\n }\n this.places = [];\n this.data = undefined;\n }\n\n /**\n * Remove the places and detach every listener (style.load, clicks,\n * hovers). Call when disposing of the layer (the map is left untouched).\n */\n destroy(): void {\n this.destroyed = true;\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.map.off(\"click\", this.pointsLayerId, this.handlePlaceClick);\n this.map.off(\"mouseenter\", this.pointsLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.pointsLayerId, this.handleMouseLeave);\n if (this.cluster) {\n this.map.off(\"click\", this.clustersLayerId, this.handleClusterClick);\n this.map.off(\"mouseenter\", this.clustersLayerId, this.handleMouseEnter);\n this.map.off(\"mouseleave\", this.clustersLayerId, this.handleMouseLeave);\n }\n this.clear();\n }\n}\n\n/** Bounding box of a non-empty place list, as MapLibre `fitBounds` corners. */\nfunction boundsOf(\n places: Place[],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const { lon, lat } of places) {\n if (lon < minLng) minLng = lon;\n if (lat < minLat) minLat = lat;\n if (lon > maxLng) maxLng = lon;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n/**\n * Pull the origin's rows out of a `POST /matrix` response\n * (`{\"durations\": [[…]], \"distances\": [[…]]}`, row-major, one row here\n * because we send a single source). Throws on anything else.\n */\nfunction matrixRows(payload: unknown): {\n durations: (number | null)[];\n distances: (number | null)[] | undefined;\n} {\n if (typeof payload !== \"object\" || payload === null) {\n throw new Error(\"matrix returned a non-object response\");\n }\n const obj = payload as Record<string, unknown>;\n const durations = firstRow(obj[\"durations\"]);\n if (!durations) {\n throw new Error(\"matrix response has no durations row\");\n }\n return { durations, distances: firstRow(obj[\"distances\"]) };\n}\n\n/** The first row of a row-major `(number | null)[][]`, if that is the shape. */\nfunction firstRow(value: unknown): (number | null)[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const row: unknown = value[0];\n if (!Array.isArray(row)) return undefined;\n return row.map((cell: unknown) =>\n typeof cell === \"number\" && Number.isFinite(cell) ? cell : null,\n );\n}\n","/**\n * NavigationCamera - the turnkey chase-cam for turn-by-turn navigation.\n *\n * Packages the Google-Maps-style follow camera on top of MapLibre's native\n * camera: per-fix `easeTo` with linear easing (continuous glide, no\n * rubber-banding), course-up bearing, a tilted pitch preset, and a\n * screen-offset that anchors the puck low-centre so the camera looks ahead.\n * User gestures (drag, rotate, pitch, zoom) switch the camera to `\"free\"`\n * mode; it auto-recentres after a configurable idle period. An `overview()`\n * mode fits the whole route top-down, and `resume()` returns to the chase\n * cam at the last known fix.\n *\n * Like `RouteLayer`, the class holds only a structural handle on the map\n * (`easeTo`, `fitBounds`, `stop`, events, container) so it is unit-testable\n * against a fake without a WebGL context.\n *\n * Globe projection note: {@link NavigationCamera.isSupported} returns\n * `false` when the map runs the globe (or vertical-perspective) projection.\n * At navigation zooms globe renders much like mercator, but the pixel-offset\n * anchor maths and the top-down overview framing assume a mercator camera;\n * switch the map to mercator (`map.setProjection({ type: \"mercator\" })`)\n * before navigating, or accept an unanchored follow.\n */\nimport type { Map as MlMap } from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport type { PositionPuck } from \"./puck.js\";\nimport type { ParsedRoute, RouteGeometry } from \"./types.js\";\n\n/** A GPS fix to follow. */\nexport interface CameraFix {\n lat: number;\n lon: number;\n}\n\n/** The camera's current behaviour. */\nexport type NavigationCameraMode = \"follow\" | \"overview\" | \"free\";\n\nexport interface NavigationCameraOptions {\n /**\n * Camera tilt in degrees, clamped to 0-85. Default `60` - MapLibre's\n * non-experimental ceiling; values above 60 may show rendering artefacts\n * and flatten DOM-marker pucks. When the requested pitch exceeds the\n * map's `maxPitch`, the limit is raised to match.\n *\n * Precedence: this option > the Studio design's `camera.pitch` (when the\n * map is a `MapMapMap` whose theme carried `extra.nav.camera`) > the\n * built-in default.\n */\n pitch?: number;\n /**\n * Follow-mode zoom. Default `17`. Same precedence as `pitch`: option >\n * Studio design `camera.zoom` > built-in default.\n */\n zoom?: number;\n /**\n * Where the fix (and puck) sits vertically on screen, as a fraction of\n * the container height from the top, clamped to 0-1. Default `0.72` -\n * the puck rides low so the camera looks up the road ahead.\n */\n anchorY?: number;\n /**\n * Ease duration per {@link NavigationCamera.follow} call, milliseconds.\n * Default `900`, and always capped by the observed fix interval so a\n * fast fix cadence never queues up lagging animations.\n */\n easeMs?: number;\n /**\n * Idle time after the last user gesture before the camera recentres\n * itself back to follow mode, milliseconds. Default `6000`; `0` disables\n * auto-recentre (the app must call {@link NavigationCamera.resume}).\n */\n autoRecentreMs?: number;\n}\n\n/** The map-interaction events that hand the camera to the user. */\nconst INTERACTION_EVENTS = [\n \"dragstart\",\n \"rotatestart\",\n \"pitchstart\",\n \"zoomstart\",\n] as const;\n\nconst DEFAULT_PITCH = 60;\nconst DEFAULT_ZOOM = 17;\nconst DEFAULT_ANCHOR_Y = 0.72;\nconst DEFAULT_EASE_MS = 900;\nconst DEFAULT_AUTO_RECENTRE_MS = 6000;\n/** Screen padding around the route in overview mode, pixels. */\nconst OVERVIEW_PADDING_PX = 48;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Anything with a `PositionPuck`-shaped `setLocation` can be co-driven. */\ntype CoDrivenPuck = Pick<PositionPuck, \"setLocation\">;\n\n/** A follow-mode chase camera for MapMap maps. */\nexport class NavigationCamera {\n private readonly m: MlMap;\n private readonly pitch: number;\n private readonly zoom: number;\n private readonly anchorY: number;\n private readonly easeMs: number;\n private readonly autoRecentreMs: number;\n\n private currentMode: NavigationCameraMode = \"follow\";\n private puck: CoDrivenPuck | undefined;\n private lastFix: CameraFix | undefined;\n private lastCourse: number | undefined;\n private lastFixAt: number | undefined;\n private lastRoute: RouteGeometry | undefined;\n private recentreTimer: ReturnType<typeof setTimeout> | undefined;\n private destroyed = false;\n\n // Bound once so `off` in destroy() removes exactly what `on` added.\n private readonly onInteraction = (ev?: { originalEvent?: unknown }): void => {\n // Camera-driven moves (our own easeTo/fitBounds) fire the same events\n // without an `originalEvent`; only real user gestures carry one.\n if (!ev?.originalEvent || this.destroyed) return;\n this.currentMode = \"free\";\n this.m.stop();\n this.scheduleRecentre();\n };\n\n /**\n * `false` when the map runs the globe (or vertical-perspective)\n * projection, whose camera geometry breaks the low-anchor offset maths\n * and top-down overview framing. Switch to mercator for navigation.\n */\n static isSupported(map: MapMapMap | MlMap): boolean {\n const m = map instanceof MapMapMap ? map.map : map;\n const projection = (\n m as { getProjection?: () => unknown }\n ).getProjection?.();\n return !usesGlobe(projection);\n }\n\n constructor(map: MapMapMap | MlMap, options: NavigationCameraOptions = {}) {\n this.m = map instanceof MapMapMap ? map.map : map;\n // A MapMapMap built from a Studio theme may carry `extra.nav.camera`;\n // its pitch/zoom become the option defaults. Precedence: explicit\n // option > design > built-in default.\n const design = map instanceof MapMapMap ? map.navDesign?.camera : undefined;\n this.pitch = clamp(options.pitch ?? design?.pitch ?? DEFAULT_PITCH, 0, 85);\n this.zoom = options.zoom ?? design?.zoom ?? DEFAULT_ZOOM;\n this.anchorY = clamp(options.anchorY ?? DEFAULT_ANCHOR_Y, 0, 1);\n this.easeMs = Math.max(0, options.easeMs ?? DEFAULT_EASE_MS);\n this.autoRecentreMs = Math.max(\n 0,\n options.autoRecentreMs ?? DEFAULT_AUTO_RECENTRE_MS,\n );\n\n // A pitch preset above the map's ceiling would be silently clamped by\n // MapLibre; raise the ceiling to honour the preset (never lower it).\n if (this.pitch > this.m.getMaxPitch()) this.m.setMaxPitch(this.pitch);\n\n for (const event of INTERACTION_EVENTS) {\n this.m.on(event, this.onInteraction);\n }\n }\n\n /** The camera's current behaviour: `\"follow\"`, `\"overview\"` or `\"free\"`. */\n get mode(): NavigationCameraMode {\n return this.currentMode;\n }\n\n /**\n * Co-drive a {@link PositionPuck}: every {@link follow} call also\n * `setLocation`s the puck, so camera and puck never diverge.\n */\n attachPuck(puck: CoDrivenPuck): void {\n this.puck = puck;\n }\n\n /**\n * Glide the camera to a fix, course-up when `courseDeg` is given\n * (bearing is left unchanged when it is `undefined`). Each call eases\n * with linear timing over `easeMs` capped by the observed fix interval,\n * and interrupts the previous ease (no queue buildup). The fix and an\n * attached puck are always updated, but the camera only moves in\n * `\"follow\"` mode - `\"free\"` and `\"overview\"` record the fix for\n * {@link resume}.\n */\n follow(fix: CameraFix, courseDeg?: number): void {\n const now = Date.now();\n const interval =\n this.lastFixAt === undefined\n ? this.easeMs\n : Math.max(0, now - this.lastFixAt);\n this.lastFixAt = now;\n this.lastFix = fix;\n if (courseDeg !== undefined) this.lastCourse = courseDeg;\n this.puck?.setLocation(fix, courseDeg);\n if (this.currentMode !== \"follow\") return;\n this.easeToFix(fix, courseDeg, Math.min(this.easeMs, interval));\n }\n\n /**\n * Fit the route top-down (pitch 0, north-up). Pass the route geometry on\n * the first call; later calls reuse the last geometry given. A no-op\n * when no geometry has ever been provided.\n */\n overview(routeGeometry?: RouteGeometry): void {\n if (routeGeometry) this.lastRoute = routeGeometry;\n const route = this.lastRoute;\n if (!route || route.coordinates.length === 0) return;\n this.clearRecentreTimer();\n this.currentMode = \"overview\";\n this.m.fitBounds(boundsOf(route.coordinates), {\n padding: OVERVIEW_PADDING_PX,\n pitch: 0,\n bearing: 0,\n duration: this.easeMs,\n essential: true,\n });\n }\n\n /**\n * Return to follow mode, gliding back to the last fix (with its last\n * known course) when one has been recorded.\n */\n resume(): void {\n this.clearRecentreTimer();\n this.currentMode = \"follow\";\n if (this.lastFix) {\n this.easeToFix(this.lastFix, this.lastCourse, this.easeMs);\n }\n }\n\n /** Remove the map listeners and cancel any pending auto-recentre. */\n destroy(): void {\n this.destroyed = true;\n this.clearRecentreTimer();\n for (const event of INTERACTION_EVENTS) {\n this.m.off(event, this.onInteraction);\n }\n }\n\n private easeToFix(\n fix: CameraFix,\n courseDeg: number | undefined,\n duration: number,\n ): void {\n this.m.easeTo({\n center: [fix.lon, fix.lat],\n ...(courseDeg !== undefined ? { bearing: courseDeg } : {}),\n pitch: this.pitch,\n zoom: this.zoom,\n offset: [0, this.anchorOffsetY()],\n duration,\n easing: (t: number) => t,\n // Interrupt semantics: `essential` easings run even under\n // prefers-reduced-motion, and each new easeTo cancels the previous\n // one, so a fast fix cadence glides instead of queueing.\n essential: true,\n });\n }\n\n /**\n * The pixel offset that renders the followed fix at `anchorY` of the\n * container height: `(anchorY - 0.5) * height` (0.5 is the natural\n * centre; positive y moves the puck down the screen).\n */\n private anchorOffsetY(): number {\n const height = this.m.getContainer().clientHeight;\n return (this.anchorY - 0.5) * height;\n }\n\n private scheduleRecentre(): void {\n this.clearRecentreTimer();\n if (this.autoRecentreMs === 0) return;\n this.recentreTimer = setTimeout(() => {\n this.recentreTimer = undefined;\n if (this.currentMode === \"free\") this.resume();\n }, this.autoRecentreMs);\n }\n\n private clearRecentreTimer(): void {\n if (this.recentreTimer !== undefined) {\n clearTimeout(this.recentreTimer);\n this.recentreTimer = undefined;\n }\n }\n}\n\n/** South-west / north-east bounds of a coordinate list. */\nfunction boundsOf(\n coordinates: [number, number][],\n): [[number, number], [number, number]] {\n let minLng = Infinity;\n let minLat = Infinity;\n let maxLng = -Infinity;\n let maxLat = -Infinity;\n for (const [lng, lat] of coordinates) {\n if (lng < minLng) minLng = lng;\n if (lng > maxLng) maxLng = lng;\n if (lat < minLat) minLat = lat;\n if (lat > maxLat) maxLat = lat;\n }\n return [\n [minLng, minLat],\n [maxLng, maxLat],\n ];\n}\n\n// ---------------------------------------------------------------------------\n// camera.flythrough() - cinematic route replay + scrollytelling binder.\n// ---------------------------------------------------------------------------\n\n/** Mean Earth radius in metres (IUGG), matching places.ts. */\nconst FLYTHROUGH_EARTH_RADIUS_M = 6371008.8;\n\n/** Straight-line (haversine) distance between two `[lng, lat]`s, metres. */\nfunction flythroughDistanceM(a: [number, number], b: [number, number]): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLat = rad(b[1] - a[1]);\n const dLon = rad(b[0] - a[0]);\n const h =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLon / 2) ** 2;\n return 2 * FLYTHROUGH_EARTH_RADIUS_M * Math.asin(Math.sqrt(h));\n}\n\n/**\n * Initial great-circle bearing from `a` to `b`, degrees clockwise from\n * north, normalised to `[0, 360)`.\n */\nexport function bearingBetween(\n a: [number, number],\n b: [number, number],\n): number {\n const rad = (deg: number): number => (deg * Math.PI) / 180;\n const dLon = rad(b[0] - a[0]);\n const latA = rad(a[1]);\n const latB = rad(b[1]);\n const y = Math.sin(dLon) * Math.cos(latB);\n const x =\n Math.cos(latA) * Math.sin(latB) -\n Math.sin(latA) * Math.cos(latB) * Math.cos(dLon);\n const deg = (Math.atan2(y, x) * 180) / Math.PI;\n return (deg + 360) % 360;\n}\n\n/**\n * The signed shortest-arc rotation from bearing `from` to bearing `to`,\n * in `(-180, 180]` degrees - the slerp-style delta the flythrough eases\n * along so the chase cam never spins the long way round.\n */\nexport function shortestArcDelta(from: number, to: number): number {\n const delta = (((to - from) % 360) + 540) % 360 - 180;\n return delta === -180 ? 180 : delta;\n}\n\n/** A camera pose along a flythrough: where to look from, and which way. */\nexport interface FlythroughPose {\n /** Camera target on the route, `[lng, lat]`. */\n center: [number, number];\n /** Chase-cam bearing: towards a point `lookAheadM` up the road. */\n bearing: number;\n}\n\n/**\n * Precomputed arc-length sampler over a route line: maps progress\n * `t` (0-1 of total route distance) to a {@link FlythroughPose}. Pure -\n * shared by {@link flythroughPose} (tests) and the controller (per frame,\n * without recomputing cumulative distances).\n */\nclass PoseSampler {\n private readonly points: [number, number][];\n private readonly cumulative: number[];\n readonly totalM: number;\n\n constructor(coordinates: [number, number][]) {\n // Consecutive duplicates carry no direction; drop them once here.\n this.points = coordinates.filter(\n (p, i) =>\n i === 0 ||\n p[0] !== coordinates[i - 1]![0] ||\n p[1] !== coordinates[i - 1]![1],\n );\n if (this.points.length < 2) {\n throw new Error(\n \"flythrough needs a route with at least two distinct coordinates\",\n );\n }\n this.cumulative = [0];\n for (let i = 1; i < this.points.length; i++) {\n this.cumulative.push(\n this.cumulative[i - 1]! +\n flythroughDistanceM(this.points[i - 1]!, this.points[i]!),\n );\n }\n this.totalM = this.cumulative[this.cumulative.length - 1]!;\n }\n\n /** The interpolated point `distanceM` along the route (clamped). */\n pointAt(distanceM: number): [number, number] {\n const d = Math.min(this.totalM, Math.max(0, distanceM));\n // Linear scan is fine: callers advance monotonically and routes are\n // a few thousand points at most.\n let i = 1;\n while (i < this.cumulative.length - 1 && this.cumulative[i]! < d) i++;\n const before = this.cumulative[i - 1]!;\n const span = this.cumulative[i]! - before;\n const f = span > 0 ? (d - before) / span : 0;\n const a = this.points[i - 1]!;\n const b = this.points[i]!;\n return [a[0] + (b[0] - a[0]) * f, a[1] + (b[1] - a[1]) * f];\n }\n\n /** The pose at progress `t` (clamped 0-1), chasing `lookAheadM` ahead. */\n poseAt(t: number, lookAheadM: number): FlythroughPose {\n const d = Math.min(1, Math.max(0, t)) * this.totalM;\n const center = this.pointAt(d);\n let target = this.pointAt(d + Math.max(1, lookAheadM));\n if (target[0] === center[0] && target[1] === center[1]) {\n // At (or past) the end the look-ahead collapses onto the centre;\n // hold the final segment's direction instead of a degenerate\n // zero-length bearing.\n const last = this.points[this.points.length - 1]!;\n const prev = this.points[this.points.length - 2]!;\n return { center, bearing: bearingBetween(prev, last) };\n }\n return { center, bearing: bearingBetween(center, target) };\n }\n}\n\n/**\n * The camera pose at progress `t` (0-1) along a route: the interpolated\n * point that fraction of the total distance along the line, with a\n * chase-cam bearing towards the point `lookAheadM` further on. Pure -\n * exported for tests and for apps that drive the camera themselves.\n */\nexport function flythroughPose(\n coordinates: [number, number][],\n t: number,\n lookAheadM = 200,\n): FlythroughPose {\n return new PoseSampler(coordinates).poseAt(t, lookAheadM);\n}\n\nexport interface FlythroughOptions {\n /**\n * Camera tilt in degrees, clamped 0-85. Default `60` (the cinematic\n * chase look; see {@link NavigationCameraOptions.pitch} for caveats\n * above 60).\n */\n pitch?: number;\n /** Camera zoom held through the replay. Default `16`. */\n zoom?: number;\n /**\n * Total replay duration in milliseconds. Default `20000`. Ignored when\n * `speedMps` is given.\n */\n durationMs?: number;\n /**\n * Replay ground speed in metres/second along the route - the duration\n * becomes `routeLength / speedMps`. Wins over `durationMs`.\n */\n speedMps?: number;\n /**\n * How far up the road the chase cam looks to derive its bearing,\n * metres. Default `200`; larger = calmer bearing on wiggly roads.\n */\n lookAheadM?: number;\n /**\n * Bearing smoothing rate per second (the fraction of the remaining\n * shortest-arc turn closed each second). Default `3`; higher = snappier.\n */\n bearingEase?: number;\n}\n\n/** The handle a {@link flythrough} returns. */\nexport interface FlythroughController {\n /** Start (or resume) the replay. Restarts from 0 when it had finished. */\n play(): void;\n /** Freeze the replay where it is. */\n pause(): void;\n /** Pause and rewind to the start (the camera jumps to the start pose). */\n stop(): void;\n /** Scrub to progress `t` (0-1, clamped) and apply the pose immediately. */\n seek(t: number): void;\n /** Playback-rate multiplier (`1` = real duration, `2` = double). */\n speed: number;\n /** Current progress, 0-1. */\n readonly progress: number;\n /** Whether the replay is currently advancing. */\n readonly playing: boolean;\n /** Subscribe to progress updates; returns the unsubscribe function. */\n onProgress(listener: (t: number) => void): () => void;\n /** Pause and detach everything. The controller is dead afterwards. */\n destroy(): void;\n}\n\n/** One animation frame, with a cancel handle; setTimeout fallback in Node. */\nfunction scheduleFrame(cb: (timestampMs: number) => void): () => void {\n if (typeof requestAnimationFrame === \"function\") {\n const handle = requestAnimationFrame(cb);\n return () => cancelAnimationFrame(handle);\n }\n const handle = setTimeout(() => cb(Date.now()), 16);\n return () => clearTimeout(handle);\n}\n\n/**\n * Cinematic route replay: fly the camera along a route line with a\n * chase-cam bearing (eased along the shortest arc, so junctions glide\n * instead of spinning), at a configurable pitch/zoom/speed. Returns a\n * transport-style controller; nothing moves until `play()` or `seek()`.\n *\n * ```ts\n * const route = await routes.route(from, to);\n * const replay = flythrough(map, route, { pitch: 60, durationMs: 15000 });\n * replay.onProgress((t) => scrubber.value = String(t));\n * replay.play();\n * ```\n *\n * Drives the camera with `jumpTo` once per animation frame (the standard\n * MapLibre scrub pattern). Runs under any projection; on globe the ride is\n * unanchored but valid. Accepts a `ParsedRoute` (from `RouteLayer`) or a\n * bare GeoJSON LineString geometry.\n */\nexport function flythrough(\n map: MapMapMap | MlMap,\n route: RouteGeometry | ParsedRoute,\n options: FlythroughOptions = {},\n): FlythroughController {\n const m = map instanceof MapMapMap ? map.map : map;\n const geometry = \"geometry\" in route ? route.geometry : route;\n const sampler = new PoseSampler(geometry.coordinates);\n const pitch = clamp(options.pitch ?? 60, 0, 85);\n const zoom = options.zoom ?? 16;\n const lookAheadM = options.lookAheadM ?? 200;\n const bearingEase = Math.max(0, options.bearingEase ?? 3);\n const durationMs =\n options.speedMps !== undefined && options.speedMps > 0\n ? (sampler.totalM / options.speedMps) * 1000\n : Math.max(1, options.durationMs ?? 20_000);\n\n let t = 0;\n let rate = 1;\n let playing = false;\n let destroyed = false;\n let bearing: number | undefined;\n let lastFrameTs: number | undefined;\n let cancelFrame: (() => void) | undefined;\n const listeners = new Set<(t: number) => void>();\n\n const applyPose = (dtS: number): void => {\n const pose = sampler.poseAt(t, lookAheadM);\n // Ease the bearing along the shortest arc: close a time-scaled\n // fraction of the remaining turn each frame (frame-rate independent).\n bearing =\n bearing === undefined\n ? pose.bearing\n : bearing +\n shortestArcDelta(bearing, pose.bearing) *\n Math.min(1, bearingEase * dtS);\n m.jumpTo({ center: pose.center, bearing, pitch, zoom });\n for (const listener of listeners) listener(t);\n };\n\n const frame = (timestampMs: number): void => {\n if (!playing || destroyed) return;\n const dtS =\n lastFrameTs === undefined ? 0 : Math.max(0, timestampMs - lastFrameTs) / 1000;\n lastFrameTs = timestampMs;\n t = Math.min(1, t + (dtS * 1000 * rate) / durationMs);\n applyPose(dtS || 1 / 60);\n if (t >= 1) {\n playing = false;\n return;\n }\n cancelFrame = scheduleFrame(frame);\n };\n\n const pause = (): void => {\n playing = false;\n cancelFrame?.();\n cancelFrame = undefined;\n lastFrameTs = undefined;\n };\n\n return {\n play(): void {\n if (destroyed || playing) return;\n if (t >= 1) t = 0; // replay from the top once finished\n playing = true;\n lastFrameTs = undefined;\n cancelFrame = scheduleFrame(frame);\n },\n pause,\n stop(): void {\n if (destroyed) return;\n pause();\n t = 0;\n bearing = undefined; // next pose snaps rather than unwinding the arc\n applyPose(1 / 60);\n },\n seek(to: number): void {\n if (destroyed) return;\n t = Math.min(1, Math.max(0, to));\n applyPose(1 / 60);\n },\n get speed(): number {\n return rate;\n },\n set speed(value: number) {\n if (Number.isFinite(value) && value > 0) rate = value;\n },\n get progress(): number {\n return t;\n },\n get playing(): boolean {\n return playing;\n },\n onProgress(listener: (progress: number) => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n destroy(): void {\n destroyed = true;\n pause();\n listeners.clear();\n },\n };\n}\n\n/** Anything scrollable the binder accepts: an element or the window. */\ntype ScrollTarget = Pick<\n HTMLElement,\n \"addEventListener\" | \"removeEventListener\"\n> &\n Partial<\n Pick<HTMLElement, \"scrollTop\" | \"scrollHeight\" | \"clientHeight\"> &\n Pick<Window, \"scrollY\" | \"innerHeight\" | \"document\">\n >;\n\n/**\n * Scrollytelling: bind a flythrough to a scroll position, so scrolling a\n * story column scrubs the camera along the route. The binder pauses the\n * controller (scroll owns the timeline) and seeks it to the scrolled\n * fraction - immediately on bind, then on every scroll. Returns the\n * unbind function.\n *\n * ```ts\n * const replay = flythrough(map, route);\n * const unbind = bindFlythroughToScroll(replay, document.querySelector(\"#story\")!);\n * ```\n */\nexport function bindFlythroughToScroll(\n controller: FlythroughController,\n target: HTMLElement | Window = window,\n): () => void {\n const t = target as ScrollTarget;\n const fraction = (): number => {\n if (typeof t.scrollTop === \"number\") {\n // An element: how far through its own scrollable height.\n const max = (t.scrollHeight ?? 0) - (t.clientHeight ?? 0);\n return max > 0 ? t.scrollTop / max : 0;\n }\n // The window: how far through the document.\n const doc = t.document?.documentElement;\n const max = (doc?.scrollHeight ?? 0) - (t.innerHeight ?? 0);\n return max > 0 ? (t.scrollY ?? 0) / max : 0;\n };\n const onScroll = (): void => {\n controller.pause();\n controller.seek(Math.min(1, Math.max(0, fraction())));\n };\n t.addEventListener(\"scroll\", onScroll, { passive: true });\n onScroll();\n return () => t.removeEventListener(\"scroll\", onScroll);\n}\n\n/**\n * Whether a `getProjection()` result names the globe. MapLibre v5 returns\n * `{ type }` where `type` is `\"globe\"`, `\"mercator\"`,\n * `\"vertical-perspective\"` or a style expression that can evaluate to any\n * of them; any mention of globe/vertical-perspective counts as globe.\n */\nfunction usesGlobe(projection: unknown): boolean {\n if (projection === null || projection === undefined) return false;\n if (typeof projection === \"string\") {\n return projection === \"globe\" || projection === \"vertical-perspective\";\n }\n if (Array.isArray(projection)) return projection.some(usesGlobe);\n if (typeof projection === \"object\") {\n return Object.values(projection).some(usesGlobe);\n }\n return false;\n}\n","/**\n * IsochroneLayer - walkability rings (reachability contours) on a MapMap\n * map, backed by the gateway's live `POST /isochrone` endpoint (Valhalla\n * isochrone; see docs/API.md).\n *\n * One call - `showReachability({ origin, mode: \"walk\", minutes: [5, 10, 15] })` -\n * renders concentric reachability rings: graduated-opacity fills (nearest\n * ring strongest), contour outlines, and \"N min\" labels along each\n * contour. The estate-agent / store-catchment / \"how walkable is this\n * flat?\" view in one line.\n *\n * Follows the RouteLayer pattern: gateway base URL/key picked up from a\n * `MapMapMap` automatically, layers survive `setStyle` theme swaps via\n * re-installation on `style.load`, and `clear()`/`destroy()` tidy up.\n */\nimport type {\n DataDrivenPropertyValueSpecification,\n FillLayerSpecification,\n GeoJSONSource,\n LineLayerSpecification,\n Map as MlMap,\n SymbolLayerSpecification,\n} from \"maplibre-gl\";\nimport { MapMapMap } from \"./map.js\";\nimport { SIGNAL_BLUE } from \"./route.js\";\nimport { toLngLat } from \"./coords.js\";\nimport type { LngLatLike } from \"./types.js\";\n\n/**\n * Travel mode for the rings. The friendly names map onto gateway costings\n * (`walk` → `pedestrian`, `cycle` → `bicycle`, `drive` → `auto`); any\n * other string is passed through as a raw Valhalla costing (e.g.\n * `\"truck\"`, `\"motor_scooter\"`).\n */\nexport type ReachabilityMode =\n | \"walk\"\n | \"cycle\"\n | \"drive\"\n | \"truck\"\n | (string & {});\n\nconst MODE_TO_COSTING: Record<string, string> = {\n walk: \"pedestrian\",\n cycle: \"bicycle\",\n drive: \"auto\",\n};\n\nexport interface ShowReachabilityOptions {\n /** Where the rings radiate from. */\n origin: LngLatLike;\n /** Travel mode. Defaults to `\"walk\"` - these are walkability rings. */\n mode?: ReachabilityMode;\n /** Ring contours in minutes, e.g. `[5, 10, 15]`. At least one. */\n minutes: number[];\n /** Ring colour. Defaults to MapMap signal blue. */\n color?: string;\n /**\n * Valhalla-style costing options forwarded verbatim, e.g.\n * `{ pedestrian: { use_lit: 1.0 } }`.\n */\n costingOptions?: Record<string, unknown>;\n}\n\nexport interface IsochroneLayerOptions {\n /** Gateway base URL. Defaults to the map's `baseUrl` when given a map. */\n baseUrl?: string;\n /** Gateway API key. Defaults to the map's `apiKey` when given a map. */\n apiKey?: string;\n /** Unique id prefix for the source/layers. Defaults to `\"mapmap-isochrone\"`. */\n id?: string;\n}\n\n/** The GeoJSON FeatureCollection the gateway returns, passed through. */\nexport interface IsochroneFeatureCollection {\n type: \"FeatureCollection\";\n features: {\n type: \"Feature\";\n geometry: { type: string; coordinates: unknown };\n properties?: Record<string, unknown> | null;\n }[];\n}\n\n/** Renders reachability rings from the gateway's `POST /isochrone`. */\nexport class IsochroneLayer {\n private readonly map: MlMap;\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly sourceId: string;\n private readonly fillLayerId: string;\n private readonly lineLayerId: string;\n private readonly labelLayerId: string;\n private lastData: IsochroneFeatureCollection | undefined;\n private lastMinutes: number[] = [];\n private lastColor: string = SIGNAL_BLUE;\n\n constructor(map: MapMapMap | MlMap, options: IsochroneLayerOptions = {}) {\n if (map instanceof MapMapMap) {\n this.map = map.map;\n this.baseUrl = (options.baseUrl ?? map.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey ?? map.apiKey;\n } else {\n this.map = map;\n if (!options.baseUrl) {\n throw new Error(\n \"IsochroneLayer needs a baseUrl when given a raw MapLibre map\",\n );\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n const id = options.id ?? \"mapmap-isochrone\";\n this.sourceId = `${id}-src`;\n this.fillLayerId = `${id}-fill`;\n this.lineLayerId = `${id}-line`;\n this.labelLayerId = `${id}-label`;\n // RouteLayer lifecycle: runtime sources/layers are wiped on every\n // setStyle (theme swap), so re-install on each style.load - which also\n // completes a show() that arrived before the style finished loading.\n this.map.on(\"style.load\", this.handleStyleLoad);\n }\n\n private readonly handleStyleLoad = (): void => {\n if (this.lastData) this.install(this.lastData);\n };\n\n /**\n * Fetch and render reachability rings. Returns the GeoJSON\n * FeatureCollection the gateway produced (each feature carries a\n * `contour` property in minutes), for callers who also want the raw\n * shapes. Replaces any rings already shown by this layer.\n */\n async showReachability(\n options: ShowReachabilityOptions,\n ): Promise<IsochroneFeatureCollection> {\n if (options.minutes.length === 0) {\n throw new Error(\n \"showReachability needs at least one contour in minutes, e.g. { minutes: [5, 10, 15] }\",\n );\n }\n const [lon, lat] = toLngLat(options.origin);\n const mode = options.mode ?? \"walk\";\n const body: Record<string, unknown> = {\n locations: [{ lat, lon }],\n costing: MODE_TO_COSTING[mode] ?? mode,\n // Largest first so smaller (nearer) rings paint on top.\n contours: [...options.minutes]\n .sort((a, b) => b - a)\n .map((time) => ({ time })),\n polygons: true,\n };\n if (options.costingOptions) body[\"costing_options\"] = options.costingOptions;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/isochrone`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n const payload: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof payload === \"object\" && payload !== null\n ? (payload as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `isochrone request failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (\n typeof payload !== \"object\" ||\n payload === null ||\n (payload as Record<string, unknown>)[\"type\"] !== \"FeatureCollection\"\n ) {\n throw new Error(\"isochrone returned no FeatureCollection\");\n }\n const collection = payload as IsochroneFeatureCollection;\n this.lastMinutes = [...options.minutes].sort((a, b) => a - b);\n this.lastColor = options.color ?? SIGNAL_BLUE;\n this.draw(collection);\n return collection;\n }\n\n /** The most recently drawn rings, if any. */\n get current(): IsochroneFeatureCollection | undefined {\n return this.lastData;\n }\n\n /** Draw (or update) a ring collection. Safe before the style has loaded. */\n private draw(collection: IsochroneFeatureCollection): void {\n this.lastData = collection;\n if (!this.map.isStyleLoaded()) return; // installed by handleStyleLoad\n this.install(collection);\n }\n\n /** Add-or-update the source and ring layers on the current style. */\n private install(collection: IsochroneFeatureCollection): void {\n const existing = this.map.getSource(this.sourceId) as\n | GeoJSONSource\n | undefined;\n if (existing) {\n existing.setData(collection as never);\n } else {\n this.map.addSource(this.sourceId, {\n type: \"geojson\",\n data: collection as never,\n });\n }\n if (this.map.getLayer(this.fillLayerId)) {\n // Re-shown with a different colour/contours: refresh the paints.\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-color\",\n this.lastColor,\n );\n this.map.setPaintProperty(\n this.fillLayerId,\n \"fill-opacity\",\n this.fillOpacity(),\n );\n this.map.setPaintProperty(this.lineLayerId, \"line-color\", this.lastColor);\n return;\n }\n\n // Valhalla polygons are full disks (not donuts), so translucent fills\n // naturally stack: near the origin every ring overlaps and the tint\n // reads strongest, fading towards the outermost contour. The graduated\n // per-ring opacity reinforces that.\n const fill: FillLayerSpecification = {\n id: this.fillLayerId,\n type: \"fill\",\n source: this.sourceId,\n paint: {\n \"fill-color\": this.lastColor,\n \"fill-opacity\": this.fillOpacity(),\n },\n };\n const line: LineLayerSpecification = {\n id: this.lineLayerId,\n type: \"line\",\n source: this.sourceId,\n paint: {\n \"line-color\": this.lastColor,\n \"line-width\": 1.5,\n \"line-opacity\": 0.8,\n },\n };\n const label: SymbolLayerSpecification = {\n id: this.labelLayerId,\n type: \"symbol\",\n source: this.sourceId,\n layout: {\n \"symbol-placement\": \"line\",\n \"text-field\": [\n \"concat\",\n [\"to-string\", [\"get\", \"contour\"]],\n \" min\",\n ],\n // Ships with the MapMap default styles (see places.ts).\n \"text-font\": [\"Noto Sans Regular\"],\n \"text-size\": 11,\n },\n paint: {\n \"text-color\": this.lastColor,\n \"text-halo-color\": \"#ffffff\",\n \"text-halo-width\": 1.2,\n },\n };\n this.map.addLayer(fill);\n this.map.addLayer(line);\n this.map.addLayer(label);\n }\n\n /**\n * Graduated fill opacity: the nearest contour (fewest minutes) is the\n * most opaque, the farthest the faintest, interpolated on each\n * feature's `contour` property. With one contour it is a constant.\n */\n private fillOpacity(): DataDrivenPropertyValueSpecification<number> {\n const min = this.lastMinutes[0] ?? 0;\n const max = this.lastMinutes[this.lastMinutes.length - 1] ?? 0;\n if (this.lastMinutes.length < 2 || min === max) return 0.18;\n return [\n \"interpolate\",\n [\"linear\"],\n [\"get\", \"contour\"],\n min,\n 0.28,\n max,\n 0.08,\n ] as unknown as DataDrivenPropertyValueSpecification<number>;\n }\n\n /** Remove the rings' layers and source from the map. */\n clear(): void {\n for (const layerId of [\n this.labelLayerId,\n this.lineLayerId,\n this.fillLayerId,\n ]) {\n if (this.map.getLayer(layerId)) this.map.removeLayer(layerId);\n }\n if (this.map.getSource(this.sourceId)) this.map.removeSource(this.sourceId);\n this.lastData = undefined;\n }\n\n /** Remove the rings and detach the layer's `style.load` listener. */\n destroy(): void {\n this.map.off(\"style.load\", this.handleStyleLoad);\n this.clear();\n }\n}\n","/**\n * AdrCheck - optional helper for the gateway's `POST /adr/check` endpoint.\n *\n * The ADR 8.6.4 tunnel compliance engine, exposed directly. No MapLibre\n * dependency; just a typed fetch wrapper.\n */\nimport type { AdrCheckRequest, AdrCheckResult } from \"./types.js\";\n\n/**\n * Builds the exact wire body the gateway deserialises\n * (`sn-gateway` `routes/adr.rs` → `sn_adr::AdrVehicleProfile`):\n * `{\"adr\": {\"dimensions\": {…}, \"tunnel_code\"?, \"hazmat\"}, \"tunnel_category\"}`.\n * Unset dimensions default to the EU 96/53/EC artic maximums, mirroring\n * `TruckDimensions::default()`. Exported for contract tests.\n */\nexport function buildAdrCheckBody(request: AdrCheckRequest): Record<string, unknown> {\n const dims = request.dimensions ?? {};\n const adr: Record<string, unknown> = {\n dimensions: {\n height_m: dims.heightM ?? 4.0,\n width_m: dims.widthM ?? 2.55,\n length_m: dims.lengthM ?? 16.5,\n gross_weight_t: dims.grossWeightT ?? 40.0,\n axle_load_t: dims.axleLoadT ?? null,\n axle_count: dims.axleCount ?? null,\n },\n hazmat: request.hazmat,\n };\n // Omitted entirely when unknown: the gateway reads a missing tunnel_code\n // as \"dangerous goods of unknown code\" (conservative code-B fallback).\n if (request.tunnelCode !== undefined) adr[\"tunnel_code\"] = request.tunnelCode;\n return { adr, tunnel_category: request.tunnelCategory };\n}\n\nexport interface AdrCheckOptions {\n /** Gateway base URL, e.g. `https://api.mapmap.ai`. */\n baseUrl: string;\n /** Gateway API key (`snk_…`). */\n apiKey?: string;\n}\n\n/** Calls `POST /adr/check` and returns the parsed compliance decision. */\nexport class AdrCheck {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n\n constructor(options: AdrCheckOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n async check(request: AdrCheckRequest): Promise<AdrCheckResult> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.apiKey) headers[\"Authorization\"] = `Bearer ${this.apiKey}`;\n\n const response = await fetch(`${this.baseUrl}/adr/check`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(buildAdrCheckBody(request)),\n });\n\n const body: unknown = await response.json().catch(() => null);\n if (!response.ok) {\n // The gateway's errors are RFC 9457 problem+json; surface title/detail.\n const problem =\n typeof body === \"object\" && body !== null\n ? (body as Record<string, unknown>)\n : undefined;\n const context = [problem?.[\"title\"], problem?.[\"detail\"]]\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\n .join(\" - \");\n throw new Error(\n `ADR check failed: HTTP ${response.status}${context ? ` (${context})` : \"\"}`,\n );\n }\n if (typeof body !== \"object\" || body === null) {\n throw new Error(\"ADR check returned a non-object response\");\n }\n const obj = body as Record<string, unknown>;\n const result: AdrCheckResult = {\n status: typeof obj[\"status\"] === \"string\" ? obj[\"status\"] : \"unknown\",\n raw: obj,\n };\n if (typeof obj[\"reason\"] === \"string\") result.reason = obj[\"reason\"];\n return result;\n }\n}\n","/**\n * Turn-by-turn guidance helpers: voice + banner instructions and lanes.\n *\n * The gateway's OSRM endpoint returns Mapbox-shaped `voiceInstructions`\n * (plain + SSML announcements with distance triggers) and\n * `bannerInstructions` (primary line with a maneuver glyph, lane\n * sub-banners) on each step when requested with\n * `voice: true` / `banner: true` route options. This module extracts them\n * from a parsed route, renders a banner as a DOM element, and speaks\n * announcements through the browser's `SpeechSynthesis`.\n *\n * Everything except {@link GuidanceBanner} and {@link speak} is pure and\n * covered by unit tests.\n */\n\nimport type { NavBannerDesign } from \"./nav-design.js\";\nimport type { ParsedRoute } from \"./types.js\";\n\n/** A spoken instruction with its trigger distance before the maneuver. */\nexport interface VoiceInstruction {\n /** Metres before the end of the step at which to announce. */\n distanceAlongGeometry: number;\n /** Plain text for speech synthesis. */\n announcement: string;\n /** SSML form, preferred by engines that support it. */\n ssmlAnnouncement?: string;\n}\n\n/** One lane entry of a banner lane diagram. */\nexport interface LaneIndication {\n /** Turn directions this lane allows (OSRM indication strings). */\n directions: string[];\n /**\n * Whether the lane can be used for the maneuver. `undefined` means\n * unknown, not unusable — banner components omit the flag for\n * non-recommended lanes (see {@link bannerLanes}).\n */\n valid?: boolean;\n /** Whether guidance recommends this lane. */\n active?: boolean;\n}\n\n/** A typed fragment of banner content. */\nexport interface BannerComponent {\n type: string;\n text: string;\n directions?: string[];\n active?: boolean;\n}\n\n/** One banner line. */\nexport interface BannerContent {\n text: string;\n type?: string;\n modifier?: string;\n components?: BannerComponent[];\n}\n\n/** The visual banner shown while travelling a step. */\nexport interface BannerInstruction {\n distanceAlongGeometry: number;\n primary: BannerContent;\n secondary?: BannerContent;\n sub?: BannerContent;\n}\n\n/** Guidance data for one step of the route. */\nexport interface StepGuidance {\n /** Step index within the flattened route. */\n stepIndex: number;\n /** Step length in metres. */\n distanceM: number;\n /**\n * Written instruction for the step's upcoming maneuver. Taken from\n * `maneuver.instruction` when a server emits it (Mapbox-style); the\n * MapMap gateway does not, so it falls back to the step's final voice\n * announcement (the pre-transition instruction) and then to the banner\n * primary text. Undefined only when the step carries no guidance at all.\n */\n instruction?: string;\n /** Spoken announcements, ordered by descending trigger distance. */\n voice: VoiceInstruction[];\n /** Visual banners for the upcoming maneuver. */\n banners: BannerInstruction[];\n}\n\n/**\n * Extracts per-step guidance from a parsed route (requires the route to\n * have been requested with `steps: true` and voice/banner enabled).\n * Steps without instructions yield empty arrays, never holes.\n */\nexport function extractGuidance(route: ParsedRoute): StepGuidance[] {\n const legs = (route.raw[\"legs\"] as Record<string, unknown>[] | undefined) ?? [];\n const out: StepGuidance[] = [];\n let index = 0;\n for (const leg of legs) {\n const steps = (leg[\"steps\"] as Record<string, unknown>[] | undefined) ?? [];\n for (const step of steps) {\n const voice = (step[\"voiceInstructions\"] as VoiceInstruction[] | undefined) ?? [];\n const banners = (step[\"bannerInstructions\"] as BannerInstruction[] | undefined) ?? [];\n out.push({\n stepIndex: index,\n distanceM: Number(step[\"distance\"] ?? 0),\n instruction: stepInstruction(step, voice, banners),\n voice,\n banners,\n });\n index += 1;\n }\n }\n return out;\n}\n\n/**\n * The written instruction for a step. The gateway's OSRM translation\n * (`sn-valhalla` `osrm.rs`) emits no `maneuver.instruction`; the written\n * text lives in the voice announcements (the last one is the pre-transition\n * instruction, e.g. \"Turn right onto High Street\") and in the banner\n * primary text. Prefer `maneuver.instruction` when a server does emit it.\n */\nfunction stepInstruction(\n step: Record<string, unknown>,\n voice: VoiceInstruction[],\n banners: BannerInstruction[],\n): string | undefined {\n const maneuver = step[\"maneuver\"] as Record<string, unknown> | undefined;\n const fromManeuver = maneuver?.[\"instruction\"];\n if (typeof fromManeuver === \"string\" && fromManeuver.length > 0) {\n return fromManeuver;\n }\n const lastVoice = voice[voice.length - 1];\n if (\n typeof lastVoice?.announcement === \"string\" &&\n lastVoice.announcement.length > 0\n ) {\n return lastVoice.announcement;\n }\n const bannerText = banners[0]?.primary?.text;\n if (typeof bannerText === \"string\" && bannerText.length > 0) {\n return bannerText;\n }\n return undefined;\n}\n\n/** Named XML entities the gateway's `xml_escape` (and standard SSML) emit. */\nconst XML_ENTITIES: Record<string, string> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \""\": '\"',\n \"'\": \"'\",\n};\n\n/**\n * Strips SSML tags down to speakable plain text. Entities are decoded in a\n * single pass (never re-scanning already-decoded output), so text whose\n * literal content looks like an entity — e.g. `&lt;`, the gateway's\n * escape of a literal `<` — round-trips correctly. Decodes the five\n * named XML entities plus decimal numeric references (`'`).\n */\nexport function ssmlToText(ssml: string): string {\n return ssml\n .replace(/<[^>]+>/g, \"\")\n .replace(/&(?:amp|lt|gt|quot|apos);|&#(\\d+);/g, (entity, decimal: string | undefined) =>\n decimal !== undefined\n ? String.fromCodePoint(Number(decimal))\n : (XML_ENTITIES[entity] ?? entity),\n )\n .trim();\n}\n\n/**\n * Lane entries of a banner's sub line, if it carries a lane diagram.\n *\n * Banner lane components only carry `active` (the recommended lane) — the\n * gateway drops the per-lane `valid` flag from banners, keeping it in the\n * raw route's `intersections[].lanes`. An active lane is by definition\n * usable, so `valid` is `true` for active lanes and *unknown* (undefined,\n * never `false`) for the rest: a non-recommended lane may still be legal.\n * Read `route.raw` `legs[].steps[].intersections[].lanes` for the full\n * `valid` set.\n */\nexport function bannerLanes(banner: BannerInstruction): LaneIndication[] {\n const components = banner.sub?.components ?? [];\n return components\n .filter((c) => c.type === \"lane\")\n .map((c) => {\n const lane: LaneIndication = { directions: c.directions ?? [] };\n if (c.active !== undefined) lane.active = c.active;\n if (c.active === true) lane.valid = true;\n return lane;\n });\n}\n\n/**\n * Unicode arrow for a lane/maneuver direction (OSRM indication strings).\n * A text-only fallback; sprite-based lane icons ship with the map assets.\n */\nexport function directionArrow(direction: string): string {\n switch (direction) {\n case \"left\":\n return \"←\";\n case \"right\":\n return \"→\";\n case \"straight\":\n case \"none\":\n return \"↑\";\n case \"slight left\":\n return \"↖\";\n case \"slight right\":\n return \"↗\";\n case \"sharp left\":\n return \"↙\";\n case \"sharp right\":\n return \"↘\";\n case \"uturn\":\n return \"↶\";\n case \"merge to left\":\n return \"⬅\";\n case \"merge to right\":\n return \"➡\";\n default:\n return \"•\";\n }\n}\n\n/** Options for {@link speak}. */\nexport interface SpeakOptions {\n /** BCP 47 language for the utterance, e.g. `en-GB`. */\n lang?: string;\n /** Speech rate (0.1–10, default 1). */\n rate?: number;\n}\n\n/**\n * Speaks a voice instruction through the browser's `SpeechSynthesis`.\n * Prefers the SSML body's text (browsers do not accept raw SSML). Returns\n * false when speech synthesis is unavailable (e.g. non-browser contexts).\n * De-duplication is the caller's responsibility: speak each instruction\n * once as its trigger distance is crossed.\n */\nexport function speak(instruction: VoiceInstruction, options: SpeakOptions = {}): boolean {\n const synth = (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n const Utterance = (\n globalThis as {\n SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance;\n }\n ).SpeechSynthesisUtterance;\n if (!synth || !Utterance) return false;\n const text = instruction.ssmlAnnouncement\n ? ssmlToText(instruction.ssmlAnnouncement)\n : instruction.announcement;\n const utterance = new Utterance(text);\n if (options.lang) utterance.lang = options.lang;\n if (options.rate) utterance.rate = options.rate;\n synth.speak(utterance);\n return true;\n}\n\n/**\n * A minimal DOM banner: primary text with a maneuver arrow, optional lane\n * row. Style with the `mapmap-banner` / `mapmap-banner-lanes` classes, pass\n * a Studio design (`extra.nav` `banner` block, e.g. `map.navDesign?.banner`)\n * to match a Studio theme, or read {@link StepGuidance} yourself for fully\n * custom UI.\n */\nexport class GuidanceBanner {\n /** The banner root element; attach it wherever your UI needs it. */\n readonly element: HTMLElement;\n private readonly design: NavBannerDesign | undefined;\n\n constructor(container?: HTMLElement, design?: NavBannerDesign) {\n const doc = (globalThis as { document?: Document }).document;\n if (!doc) throw new Error(\"GuidanceBanner requires a DOM environment\");\n this.design = design;\n this.element = doc.createElement(\"div\");\n this.element.className = \"mapmap-banner\";\n // With a design, the derived metrics follow the Studio preview exactly\n // (gap = padding × 1.2, horizontal padding = padding × 1.4, arrow at\n // fontSize × 1.4, height set = min-height with contents vertically\n // centred, unset = auto). Without one the built-in look is unchanged.\n this.element.style.cssText = design\n ? \"display:none;align-items:center;box-sizing:border-box;\" +\n `gap:${Math.round((design.padding ?? 10) * 1.2)}px;` +\n `padding:${design.padding ?? 10}px ${Math.round((design.padding ?? 10) * 1.4)}px;` +\n `background:${design.background};color:${design.textColor};` +\n `border-radius:${design.cornerRadius ?? 10}px;` +\n `max-width:${design.maxWidth ?? 340}px;` +\n (design.height !== undefined ? `min-height:${design.height}px;` : \"\") +\n `font:600 ${design.fontSize}px/1.3 system-ui,sans-serif`\n : \"display:none;gap:12px;align-items:center;padding:10px 14px;\" +\n \"background:#101418;color:#fff;border-radius:10px;\" +\n \"font:600 16px/1.3 system-ui,sans-serif\";\n container?.appendChild(this.element);\n }\n\n /** Renders a banner instruction (or hides the element with `null`). */\n update(banner: BannerInstruction | null): void {\n if (!banner) {\n this.element.style.display = \"none\";\n this.element.replaceChildren();\n return;\n }\n const doc = this.element.ownerDocument;\n this.element.style.display = \"flex\";\n\n const arrow = doc.createElement(\"span\");\n arrow.textContent = directionArrow(banner.primary.modifier ?? \"straight\");\n arrow.style.fontSize = this.design\n ? `${Math.round(this.design.fontSize * 1.4)}px`\n : \"22px\";\n\n const text = doc.createElement(\"span\");\n text.textContent = banner.primary.text;\n\n const children: HTMLElement[] = [arrow, text];\n\n const lanes = this.design?.showLanes === false ? [] : bannerLanes(banner);\n if (lanes.length > 0) {\n const laneRow = doc.createElement(\"span\");\n laneRow.className = \"mapmap-banner-lanes\";\n if (this.design) {\n // Studio preview semantics: letter-spacing scales with the padding\n // token, and each lane dims unless guidance recommends it.\n const spacing = Math.max(2, Math.round((this.design.padding ?? 10) * 0.4));\n laneRow.style.cssText = `margin-left:auto;letter-spacing:${spacing}px;white-space:nowrap`;\n for (const lane of lanes) {\n const glyph = doc.createElement(\"span\");\n glyph.textContent = directionArrow(lane.directions[0] ?? \"none\");\n glyph.style.opacity = lane.active ? \"0.95\" : \"0.35\";\n laneRow.appendChild(glyph);\n }\n } else {\n laneRow.style.cssText = \"margin-left:auto;letter-spacing:4px\";\n laneRow.textContent = lanes\n .map((lane) => directionArrow(lane.directions[0] ?? \"none\"))\n .join(\"\");\n laneRow.style.opacity = \"0.9\";\n }\n children.push(laneRow);\n }\n\n this.element.replaceChildren(...children);\n }\n}\n","/**\n * Spoken turn-by-turn guidance over the browser's `SpeechSynthesis`.\n *\n * {@link VoiceGuidance} consumes the guidance updates emitted by the\n * `@mapmap/core` wasm `GuidanceSession` (`{ state: \"navigating\" | \"arrived\"\n * | \"offRoute\", spoken?, severity?, … }`). The core already schedules each\n * spoken prompt by its trigger distance and repeats it on every update\n * until it is superseded, so the speaking rule is simple: announce each\n * `utteranceId` exactly once, the first time it appears.\n *\n * Severity (derived in the Rust core — see `InstructionSeverity`) maps to\n * prosody and earcons:\n *\n * - `info` — normal manoeuvres: base rate/pitch, no earcon by default;\n * - `warning` — approaching a restriction (toll, ferry): slight pitch\n * lift, warning earcon when configured;\n * - `critical` — prohibitions (ADR tunnel block, gate): pitch and rate\n * lift, pending speech cancelled so the prompt is never queued behind\n * chatter, critical earcon when configured.\n *\n * Off-route updates carry no instruction; they play the warning earcon\n * once per off-route episode (the app recalculates and speech resumes on\n * the new session).\n *\n * Earcons are lazy URLs (see `map-assets/earcons/`, generated by\n * `scripts/generate-earcons.py`) — nothing is bundled with the SDK.\n * Everything no-ops safely where `speechSynthesis` is unavailable\n * (non-browser contexts, some webviews).\n */\n\nimport { ssmlToText } from \"./guidance.js\";\n\n/** Instruction urgency, as emitted by the core (`InstructionSeverity`). */\nexport type GuidanceSeverity = \"info\" | \"warning\" | \"critical\";\n\n/** The spoken prompt of a core guidance update. */\nexport interface GuidanceSpokenPrompt {\n /** Plain text for speech synthesis. */\n text: string;\n /** SSML form; browsers reject raw SSML, so it is stripped to text. */\n ssml?: string | null;\n /** Metres before the manoeuvre at which the core released the prompt. */\n triggerDistanceM: number;\n /** Unique utterance id — the de-duplication key. */\n utteranceId: string;\n}\n\n/** The subset of a core guidance update that {@link VoiceGuidance} reads. */\nexport interface VoiceGuidanceUpdate {\n /** Guidance state, as emitted by the wasm `GuidanceSession`. */\n state: \"navigating\" | \"arrived\" | \"offRoute\";\n /** Spoken prompt currently due (repeated until superseded). */\n spoken?: GuidanceSpokenPrompt | null;\n /** Urgency of the current step's instruction (default `info`). */\n severity?: GuidanceSeverity;\n /** BCP 47 locale of the instruction text, when the payload carries one. */\n voiceLocale?: string;\n}\n\n/** Options for {@link VoiceGuidance}. */\nexport interface VoiceGuidanceOptions {\n /** BCP 47 language for utterances, e.g. `en-GB`. An update's\n * `voiceLocale` takes precedence when present. */\n lang?: string;\n /** Base speech rate (0.1–10, default 1). Critical prompts speak\n * slightly faster than this base. */\n rate?: number;\n /** Volume for speech and earcons, 0–1 (default 1). */\n volume?: number;\n /** Start muted. */\n muted?: boolean;\n /** Severity → earcon audio URL. Absent entries play nothing. */\n earcons?: Partial<Record<GuidanceSeverity, string>>;\n}\n\n/** Speech parameters for one severity level. */\nexport interface SeverityProsody {\n /** Utterance rate. */\n rate: number;\n /** Utterance pitch (0–2, 1 = neutral). */\n pitch: number;\n /** Whether pending speech is cancelled before this prompt. */\n interrupt: boolean;\n}\n\n/**\n * Prosody for a severity level at a base rate. Pure — exported for tests\n * and for custom voice layers that want the same house style.\n */\nexport function severityProsody(\n severity: GuidanceSeverity,\n baseRate = 1,\n): SeverityProsody {\n switch (severity) {\n case \"critical\":\n return { rate: baseRate * 1.1, pitch: 1.2, interrupt: true };\n case \"warning\":\n return { rate: baseRate, pitch: 1.1, interrupt: false };\n default:\n return { rate: baseRate, pitch: 1, interrupt: false };\n }\n}\n\n/** Severities that play their earcon by default (info stays silent so a\n * chime does not precede every routine manoeuvre). */\nconst EARCON_SEVERITIES: readonly GuidanceSeverity[] = [\"warning\", \"critical\"];\n\n/**\n * Speaks core guidance updates through the browser's `SpeechSynthesis`,\n * with severity-aware prosody, optional earcons, and mute/volume\n * controls. Feed every update from the wasm `GuidanceSession` to\n * {@link VoiceGuidance.update}.\n */\nexport class VoiceGuidance {\n private readonly options: VoiceGuidanceOptions;\n private volume: number;\n private mutedState: boolean;\n private lastUtteranceId: string | undefined;\n private offRouteAnnounced = false;\n\n constructor(options: VoiceGuidanceOptions = {}) {\n this.options = options;\n this.volume = clampVolume(options.volume ?? 1);\n this.mutedState = options.muted ?? false;\n }\n\n /** Whether this environment can speak at all. */\n get available(): boolean {\n return synth() !== undefined && utteranceCtor() !== undefined;\n }\n\n /** Whether announcements are currently muted. */\n get muted(): boolean {\n return this.mutedState;\n }\n\n /** Mute announcements (also cancels anything mid-utterance). */\n mute(): void {\n this.mutedState = true;\n synth()?.cancel();\n }\n\n /** Unmute announcements. Prompts seen while muted are not replayed. */\n unmute(): void {\n this.mutedState = false;\n }\n\n /** Set the volume for speech and earcons (clamped to 0–1). */\n setVolume(volume: number): void {\n this.volume = clampVolume(volume);\n }\n\n /**\n * Consume one guidance update. Speaks the update's prompt the first\n * time its `utteranceId` appears; plays the warning earcon once per\n * off-route episode. Safe to call in any environment.\n */\n update(update: VoiceGuidanceUpdate): void {\n if (update.state === \"offRoute\") {\n if (!this.offRouteAnnounced) {\n this.offRouteAnnounced = true;\n this.playEarcon(\"warning\");\n }\n return;\n }\n this.offRouteAnnounced = false;\n const spoken = update.spoken;\n if (!spoken || spoken.utteranceId === this.lastUtteranceId) return;\n // Record before the mute check: prompts seen while muted must not\n // replay, stale, on unmute.\n this.lastUtteranceId = spoken.utteranceId;\n this.speak(spoken, update.severity ?? \"info\", update.voiceLocale);\n }\n\n /** Cancel any speech in progress and forget the de-duplication state. */\n dispose(): void {\n synth()?.cancel();\n this.lastUtteranceId = undefined;\n this.offRouteAnnounced = false;\n }\n\n private speak(\n prompt: GuidanceSpokenPrompt,\n severity: GuidanceSeverity,\n voiceLocale: string | undefined,\n ): void {\n if (this.mutedState) return;\n const synthesis = synth();\n const Utterance = utteranceCtor();\n if (!synthesis || !Utterance) return;\n\n const prosody = severityProsody(severity, this.options.rate ?? 1);\n if (prosody.interrupt) synthesis.cancel();\n if (EARCON_SEVERITIES.includes(severity)) this.playEarcon(severity);\n\n const text = prompt.ssml ? ssmlToText(prompt.ssml) : prompt.text;\n const utterance = new Utterance(text);\n const lang = voiceLocale ?? this.options.lang;\n if (lang) utterance.lang = lang;\n utterance.rate = prosody.rate;\n utterance.pitch = prosody.pitch;\n utterance.volume = this.volume;\n synthesis.speak(utterance);\n }\n\n private playEarcon(severity: GuidanceSeverity): void {\n if (this.mutedState) return;\n const url = this.options.earcons?.[severity];\n if (!url) return;\n const AudioCtor = (globalThis as { Audio?: typeof Audio }).Audio;\n if (!AudioCtor) return;\n const audio = new AudioCtor(url);\n audio.volume = this.volume;\n // Autoplay can be rejected before a user gesture; guidance must\n // never throw over a missing chime.\n void audio.play()?.catch?.(() => {});\n }\n}\n\nfunction synth(): SpeechSynthesis | undefined {\n return (globalThis as { speechSynthesis?: SpeechSynthesis }).speechSynthesis;\n}\n\nfunction utteranceCtor(): typeof SpeechSynthesisUtterance | undefined {\n return (\n globalThis as { SpeechSynthesisUtterance?: typeof SpeechSynthesisUtterance }\n ).SpeechSynthesisUtterance;\n}\n\nfunction clampVolume(volume: number): number {\n if (!Number.isFinite(volume)) return 1;\n return Math.min(1, Math.max(0, volume));\n}\n"]}
|