Tile generators for the imagineRio Mapbox map. Two parallel pipelines:
- Vector (
index.js) — pulls features from an ArcGIS Online FeatureServer, merges + cleans them with mapshaper, and emits an XYZ pyramid of Mapbox vector tiles via tippecanoe, then syncs to S3. - Raster (
raster.js) — takes a georeferenced GeoTIFF from an S3 bucket and emits a TMS PNG pyramid via GDAL (gdal2tiles), synced to the raster bucket ass3://<BUCKET_TARGET>/<ssid>/{z}/{x}/{y}.png— the layout the map loads as arasteroverlay (schemetms), keyed by the item'sssid.
- Node 20.6+ (see
.nvmrc) tippecanoeonPATH— vector (or use Docker)- GDAL (
gdalinfo,gdalwarp,gdal2tiles.py) onPATH— raster (or use Docker) - AWS CLI v2 on
PATHwith credentials configured (or use Docker)
Copy .env.example to .env (loaded by Node's built-in --env-file-if-exists):
| Var | Pipeline | Required | Notes |
|---|---|---|---|
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION |
both | yes | AWS CLI credentials |
ARCGIS_API_KEY |
vector | yes | ArcGIS Online key for the imagineRio_GDB FeatureServer |
AWS_BUCKET |
vector | yes | Plain S3 URI prefix, e.g. s3://imaginerio-vector/base/ |
MIN_ZOOM / MAX_ZOOM |
vector | no | Tippecanoe -Z / -z, default 9 / 17 |
PROJECT |
raster | no | Label, default imaginerio |
BUCKET_SOURCE |
raster | no | Source GeoTIFF bucket, default imaginerio-rasters-temp |
BUCKET_TARGET |
raster | no | Tile target bucket, default imaginerio-rasters |
RASTER_MIN_ZOOM / RASTER_MAX_ZOOM |
raster | no | Override zoom range; max defaults to the source's native resolution, min to max − 8 |
SEARCH_API |
raster | no | imagineRio search API base URL (the site's NEXT_PUBLIC_SEARCH_API); enables the read-only DB metadata check |
On a host like Render there is no .env file — set these as the service's
environment variables instead. --env-file-if-exists loads .env locally when
it's present and skips it (rather than aborting) when it isn't.
The vector pipeline's FeatureServer URL is hardcoded in index.js.
nvm use # switches to Node 20
npm install
# vector
npm start # full pipeline: fetch → merge → tile → upload
npm run upload # rebuild tiles from existing geojson/final/ and upload
# raster
npm run raster # tile every SSID*.tif in BUCKET_SOURCE (skips already-tiled)
npm run raster -- --ssid 41988749 # one item: s3://BUCKET_SOURCE/SSID41988749.tif
npm run raster -- --key some.tif # one explicit source key
npm run raster -- --ssid 41988749 --force # re-tile even if target tiles exist
npm run lint
npm run formatVector: per-page GeoJSON is cached under geojson/; re-running npm start skips
already-fetched pages. Raster: source TIFs download to raster-src/ and tiles
build under raster-tiles/<ssid>/ before upload (both git-ignored).
docker build -t vector-tile-generator .
# vector (default)
docker run --rm --env-file .env -v "$HOME/.aws:/home/node/.aws:ro" vector-tile-generator
# raster (override the command)
docker run --rm --env-file .env -v "$HOME/.aws:/home/node/.aws:ro" \
vector-tile-generator raster.js --ssid 41988749The image is multi-stage: tippecanoe is compiled in a builder; the runtime is
node:20-bookworm-slim with awscli, GDAL, and the tippecanoe binary. The
entrypoint is node --env-file-if-exists=.env, defaulting to index.js.