⚓ A marine chart plotter, in Go.
Generate offline vector-tile archives from NOAA S-57 ENC cells and render them in the browser.
▶ Try the live demo · 📚 Read the docs →
▶ Open the live, interactive demo — official NOAA charts of Annapolis, rendered in your browser. No install, no server.
Warning
Not for navigation. This project is coded almost entirely with AI (Claude). It is an experiment in building a large, complex specification (IHO S-101) with AI, and a personal learning tool — not a certified or tested product. Do not rely on it for real-world navigation. See Known limitations for what the chart rendering does not yet do.
chartplotter turns official NOAA nautical charts into fast map tiles you can view in a web browser, online or fully offline.
It reads S-57 electronic navigational chart (ENC) cells and draws them with the
S-101 Portrayal Catalogue, the modern IHO standard for how charts look. It
writes the result to a single PMTiles archive of Mapbox Vector Tiles. A small
<chart-plotter> web component, built on
MapLibre GL JS, draws the chart.
In short: the heavy lifting happens once, up front. chartplotter reads the raw NOAA charts and renders every feature — its colors, symbols, and lines — into map tiles, saved as a single file on your machine. After that the browser only displays those tiles — panning, zooming, switching palettes — and never touches the raw charts again.
Implement the IHO chart standards — S-57 (ENC data), S-101 portrayal (the
successor to S-52), and the wider S-100 / S-102 family — in pure Go, with
minimal dependencies and no CGO, so the whole thing cross-compiles to a single
static binary for any platform with GOOS/GOARCH and nothing else to install.
- A complete chart pipeline. chartplotter does every step: ISO 8211 decode, the S-57 feature model, S-101 portrayal, web-Mercator tiling, vector-tile encode, and a streaming PMTiles writer.
- Works offline. Generate one
.pmtilesarchive for a region, then serve or ship it. You do not need a tile server to view it. - Adjust the chart live. Switch Day, Dusk, and Night palettes and toggle mariner settings — depth shading, soundings, contours, safety-depth danger highlighting — and the map restyles at once. Colors are stored as S-101 names and settings ride along as tile attributes, so the viewer applies your changes without regenerating the tiles.
- Ships as one binary. The S-101 catalogue and the web frontend build into the
program. A self-contained
chartplotter serveneeds no files on disk — you supply only the ENC cells. - Runs a server. The built-in HTTP server downloads NOAA cells, generates tiles in the background, and serves the frontend with byte-range support.
- Live position and AIS (early). Point a NMEA 0183 feed at the server (over
TCP) and it shows your own ship and basic AIS targets on the chart. A
built-in
simulatecommand generates traffic for testing.
The chart is the foundation, not the whole app. The frontend is built from a
<chart-plotter> base plus small plugins (own-ship and AIS already work this
way), and the goal is a stable plugin API so you can build other things on top
of the chart — instrument gauges, custom overlays, routes, and more — without
forking the core. NMEA 0183 own-ship and AIS are the first slice of that; expect
the surface to grow and change.
Download an archive for your platform from the
Releases page, extract it,
and put chartplotter on your PATH. Each platform ships two builds:
…_s101— self-contained: embeds the S-101 catalogue, runs with no extra files. (That catalogue is IHO material; see THIRD-PARTY-NOTICES.md.)- plain — needs
--s101 <PortrayalCatalog dir>at runtime, pointing at your own copy of the catalogue.
Requires Go 1.26+.
go install github.com/beetlebugorg/chartplotter/cmd/chartplotter@latestgit clone https://github.com/beetlebugorg/chartplotter.git
cd chartplotter
make build # -> bin/chartplotter (embeds the catalogue if it is available)
bin/chartplotter versionThe frontend is built into the binary, so one file is all you need. Start the server and open the viewer:
chartplotter serve
# open http://127.0.0.1:8080 → pick a region → it downloads and builds tiles → the chart appearsThe server writes everything it generates to your cache directory
(~/.cache/chartplotter), never into the binary's assets.
You can also build a standalone archive yourself with the bake command:
# Generate one archive from cells, a directory, or a NOAA ENC zip.
chartplotter bake -o charts.pmtiles US4MD81M.000
# Generate one archive per navigational band (best-available display).
chartplotter bake --bands -o charts.pmtiles US5MD_ENCs.zipTo develop the frontend, serve the assets from disk instead of the embedded bundle:
chartplotter serve --assets web| Command | What it does |
|---|---|
version |
Print the version and whether the S-101 catalogue is embedded. |
emit-assets DIR |
Write the S-101 client assets (color tables, sprites, line styles, patterns) to a directory. |
catalog-json IN.xml OUT.json |
Distil NOAA ENCProdCat.xml into a compact catalog.json. |
bake -o OUT.pmtiles IN… |
Generate a PMTiles archive from S-57 cells, directories, or NOAA ENC zips. |
serve [--host] [--port] [--assets DIR] |
Serve the web frontend, the baking API, and the NOAA cell proxy. |
simulate |
Run an NMEA 0183 traffic generator over TCP (own-ship + AIS targets) for testing. |
Run chartplotter <command> --help for the full flags.
S-57 ENC cell (.000)
│ ISO 8211 decode pkg/iso8211
▼
S-57 feature + geometry model pkg/s57
│ S-101 portrayal pkg/s100, internal/engine/s101
▼
Primitive drawing list (lat/lon) internal/engine/portrayal
│ project + clip internal/engine/tile
▼
Mapbox Vector Tiles internal/engine/mvt
│ dedup + streaming write internal/engine/pmtiles
▼
charts.pmtiles ───────────────▶ <chart-plotter> / MapLibre GL JS (web/)
Read the Architecture docs for the full pipeline, and the Tile Schema for the layer and field contract the frontend depends on.
make build # build bin/chartplotter
make test # go test ./...
make vet # go vet ./...
make fmt # gofmt -w .
make serve # build + serve web/ on :8080CI runs gofmt, go vet, go test, and go build on every push. When you push a
v* tag, GoReleaser cuts a release with binaries for Linux,
macOS, and Windows on amd64 and arm64.
Full docs live at beetlebugorg.github.io/chartplotter: install, the CLI reference, the chart pipeline, and the vector-tile schema.
chartplotter's own code is MIT © Jeremy Collins.
It bundles third-party software and data under their own licenses — all Go dependencies are permissive (MIT / BSD-3-Clause), plus MapLibre GL JS (BSD), Noto Sans (OFL), OpenBridge icons (CC BY 4.0), and a GSHHG coastline basemap (LGPL). NOAA ENC charts are U.S. public domain and not for navigation.
The IHO S-101 Portrayal & Feature Catalogue is © IHO and is not included in
this repository; a draft copy is embedded only in opt-in _s101 builds, and its
redistribution terms are still to be confirmed. See
THIRD-PARTY-NOTICES.md for the full inventory.