Maps on Blossom and Nostr
GM,
This is what i hacked together at the SEC.
As it turns out, through the magic of HTTP range requests, we can serve map tiles from blossom.
Check out the demo at [earthly.city](https://earthly.city):
The base map of earthly is hosted on satellite earth and I'm working on bringing it to blossom.earthly.city.
If you click on Globe icon on the left side of the toolbar you can create and deploy small throw away websites, by dragging a rect, with map chunks down to the max z-level. Im using ContextVM and nsyte to deploy it. Here is an example of such a map app: https://npub1c2rftpr5h83wjm4w6vxt0srassxv8fag5zc7zuh79p8d55uf8v0sltpz7j.nsite.earthly.city/
Try deploying an island or something small because otherwise the processing might take too long and the MCP client might time out.
You can already use this for maps that don't require full zoom: https://cdn.satellite.earth/8995fe122d595244c7051650b579e9c0b221549f9f4f4e055ee204779695a4aa.pmtiles
Its a 1.5GB file that brings you down to municipality level. This file format/library is responsible for the magic: [protomaps.com](https://protomaps.com/)
If you have a web app you can use this snippet:
```typescript
import * as PMTiles from 'pmtiles'
import ml from 'maplibre-gl'
useEffect(() => {
const protocol = new PMTiles.Protocol()
ml.addProtocol('pmtiles', protocol.tile)
return () => {
ml.removeProtocol('pmtiles')
}
}, [])
const mapSourceUrl = 'https://cdn.satellite.earth/8995fe122d595244c7051650b579e9c0b221549f9f4f4e055ee204779695a4aa.pmtiles'
const map = new ml.Map({
container: mapRef.current,
zoom: 4,
style: {
glyphs: 'https://protomaps.github.io/basemaps-assets/fonts/{fontstack}/{range}.pbf',
sprite: 'https://protomaps.github.io/basemaps-assets/sprites/v4/light',
version: 8,
sources: {
osm: {
type: 'vector',
url: pmtiles://${mapSourceUrl},
},
},
layers: mapLayers,
},
})
```
Hosting map tiles from blossom has a caveat: a full planet file has 120GB and the servers that i tried don't seem to be able to digest range requests to such files. Naturally the next step would be splitting up tile sets in digestible files.
I've implemented a demo of a composite map at https://www.earthly.city/map/combined. My VPS provider is having issues so the map loading can be very slow. Check back later if you have issues seeing the map.
<video src="https://yakihonne.s3.ap-east-1.amazonaws.com/3aa5817273c3b2f94f491840e0472f049d0f10009e23de63006166bca9b36ea3/files/1757679277038-YAKIHONNES3.mp4" controls></video>
Right now the 'announcement' is a set of a map quadrants corresponding to bounding boxes:
```typescript
// Demo PMTiles quadrants for Germany/Austria/Switzerland region
export const DEMOQUADRANTARCHIVES: Archive[] = [
{
role: 'vector-base',
hash: 'c293a371995dce686d4a97fa08d14cf1b1e299dfda13354780d7d810424b3af7', // SW quadrant
zmin: 0,
zmax: 14,
bbox: [8.221593, 46.3829795, 9.2614745, 47.422861], // SW bounds
},
{
role: 'vector-base',
hash: 'c8855bea14ca5b17a81b936c0ae9a398e87ae723ed56af5123119d22ac5c108d', // NE quadrant
zmin: 0,
zmax: 14,
bbox: [9.2614745, 47.422861, 10.301356, 48.4627425], // NE bounds
},
]
```
Implemented properly if would be a set of geohashes mapped to blossom links:
```typescript
export const DEMOQUADRANTARCHIVES: Archive[] = [
{
role: 'vector-base',
hash: 'c293a371995dce686d4a97fa08d14cf1b1e299dfda13354780d7d810424b3af7', // SW quadrant
zmin: 0,
zmax: 14,
geohash: '21m', // SW bounds
},
{
role: 'vector-base',
hash: 'c8855bea14ca5b17a81b936c0ae9a398e87ae723ed56af5123119d22ac5c108d', // NE quadrant
zmin: 0,
zmax: 14,
geohash: '21k', // NE bounds
},
]
```
This way it could be viable to construct planet.pmtiles fully from a set of 500 - 700Mb files.
sauce: nostr://npub18658qx0w7snvazn0z0dkjfzrtzpk23z8fdt0eqew7jn0vegas60sfuqrsg/relay.ngit.dev/earthly-city