Skip to content

Add vector tileset build - #92

Open
bkeepers wants to merge 2 commits into
mainfrom
pmtiles
Open

Add vector tileset build#92
bkeepers wants to merge 2 commits into
mainfrom
pmtiles

Conversation

@bkeepers

@bkeepers bkeepers commented Jun 11, 2026

Copy link
Copy Markdown
Member

Adds a packages/tiles workspace that builds a PMTiles vector tileset (neaps.pmtiles, ~15MB) of all 6,085 stations for direct integration with MapLibre GL.

  • Single stations source-layer, z0–10: lean properties (id/name/type) at z0–7 for rendering dots, full station data at z8–10. Two tippecanoe runs merged with tile-join; no station is ever dropped at any zoom.
  • Encoding: vector tile properties are scalar-only, so nested objects (datums, harmonic_constituents, offsets, source, license, epoch) are JSON-string properties that clients JSON.parse. Subordinate stations include their reference station's datums/constituents, so each feature is self-sufficient for prediction.
  • Feature ids: stable 53-bit FNV-1a hashes of station ids (collision-checked at build time), usable with MapLibre setFeatureState and consistent across releases.
  • Build: npm run build -w tiles (requires Docker; uses the pinned ghcr.io/openwatersio/tippecanoe:2.79.0 image, mirroring the packages/tcd pattern).
  • Publishing: publish.yml attaches a stable-named neaps.pmtiles to releases so releases/latest/download/neaps.pmtiles is a permanent URL; the release version is embedded in the tileset metadata description.
  • Also commits AGENTS.md with a PMTiles section and corrected packages/tcd references.

Testing

  • npm test -w tiles: 10 tests open the built file, verify header/metadata (single merged vector_layers entry spanning z0–10), assert the z0 tile contains every station under 500KB compressed, check the lean/full boundary at z7→z8, and round-trip parsed constituents/datums/offsets against the stations export for reference and subordinate stations.
  • Browser smoke test: rendered the tileset in headless MapLibre via the pmtiles protocol — 3,626 dots at z3 with a style expression matching on type; at z9 a queried feature's parsed JSON yielded 50 constituents and datums matching the source.
  • Root npm test (31,214 tests) and npm run lint pass.

@pkg-pr-new

pkg-pr-new Bot commented Jun 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@neaps/tide-database@92

commit: 24ba42e

@bkeepers

Copy link
Copy Markdown
Member Author

@joeberkovitz I am preparing to add tides to the Open Waters app, so I thought I would explore a similar approach you described for floatingtrails.com. This pull request adds a pmtiles build of the database. I would love your feedback on it.

Adds a packages/tiles workspace that builds a MapLibre-ready PMTiles
vector tileset of all stations:

- Stations are point features in a single "stations" source-layer.
  Nested objects (datums, harmonic_constituents, offsets, source,
  license, epoch) are encoded as JSON-string properties since vector
  tiles only support scalar values.
- Lean properties (id/name/type) at z0-7, full station data at z8-10,
  merged with tile-join so every tile stays small while no station is
  ever dropped.
- Feature ids are stable 53-bit FNV-1a hashes of station ids for
  MapLibre setFeatureState.
- Built with tippecanoe via the pinned ghcr.io/openwatersio/tippecanoe
  Docker image; tests decode tiles and round-trip station data against
  the stations export.
- publish.yml attaches the stable-named neaps.pmtiles to releases with
  the release version embedded in the tileset metadata.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new packages/tiles workspace that builds and tests a PMTiles vector tileset (neaps.pmtiles) for MapLibre/Mapbox Vector Tile consumers, and updates the release workflow to publish the artifact.

Changes:

  • Add a Docker-backed build pipeline that generates lean (z0–7) + full (z8–10) station tiles, then merges them into a single PMTiles file.
  • Add Vitest coverage that validates PMTiles metadata, completeness at z0, lean/full property boundaries, and round-trip JSON-encoded station fields.
  • Extend the release workflow to build and attach .pmtiles artifacts to GitHub Releases.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/tiles/test/tiles.test.ts Adds end-to-end validation of the generated PMTiles (header/metadata, zoom behavior, and property round-trips).
packages/tiles/test/pmtiles.ts Adds local-file PMTiles reader + MVT decoding utilities for tests.
packages/tiles/README.md Documents tileset usage, structure, and property encoding expectations.
packages/tiles/package.json Declares the new tiles workspace scripts and dev dependencies.
packages/tiles/features.ts Implements stable 53-bit FNV-1a feature IDs and lean/full property shaping (JSON-string encoding for nested objects).
packages/tiles/docker-compose.yml Pins and configures tippecanoe/tile-join containers used by the build.
packages/tiles/build.ts Generates deterministic NDJSON inputs and collision-checks feature IDs before tile generation.
packages/tiles/build Orchestrates the two tippecanoe builds and merges them into dist/neaps.pmtiles with metadata.
.github/workflows/publish.yml Builds PMTiles during publish and uploads .pmtiles artifacts alongside existing .tcd outputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +21
import { openSync, readSync } from "fs";
import { PMTiles, type Source, type RangeResponse } from "pmtiles";
import { VectorTile } from "@mapbox/vector-tile";
import Protobuf from "pbf";

/** Byte-range source for reading a local .pmtiles file. */
class FileSource implements Source {
private fd: number;

constructor(private path: string) {
this.fd = openSync(path, "r");
}

getKey(): string {
return this.path;
}

async getBytes(offset: number, length: number): Promise<RangeResponse> {
const buffer = Buffer.alloc(length);
readSync(this.fd, buffer, 0, length, offset);
return {
Comment thread packages/tiles/README.md
| `chart_datum` | string | Key into `datums`, e.g. `MLLW`, `LAT` |
| `disclaimers` | string | Optional |
| `datums` | JSON string | `{ "MLLW": 1.01, "MSL": 2.532, ... }` |
| `harmonic_constituents` | JSON string | `[{ "name": "M2", "amplitude", "phase" },...]` |
@bkeepers bkeepers changed the title Add PMTiles vector tileset build Add vector tileset build Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants