Skip to content

beetlebugorg/tile57

Repository files navigation

tile57

⚓ A high-performance, low-memory S-57/S-101 chart engine: vector tiles, S-52 styles, PNG and PDF.
tile57 turns IHO S-57 ENC cells into Mapbox Vector Tiles with a matching MapLibre S-52 style, or renders finished charts directly to PNG and PDF — one Zig library with a C ABI, compiled natively or to WASM.

License  ·  📚 Docs →


Warning

Not for navigation. This project is coded almost entirely with AI (Claude) and human-reviewed. It is an experiment in using AI to implement a large, complex specification from scratch — not a certified or tested navigation product. Do not rely on it for real-world navigation. See Known limitations.


Goals

tile57 is an experiment in building a real, spec-faithful nautical chart engine almost entirely with AI assistance. A few specific goals shape its design:

  • AI-written, human-reviewed. Every significant piece of this codebase was generated by Claude and reviewed by a human. The project tests how far AI can carry the heavy lifting of spec interpretation, test coverage, and implementation correctness on a non-trivial domain.

  • Spec adherence first. The goal is to implement S-57 decoding, S-101 portrayal, and S-52 display as faithfully as possible, using the actual IHO spec documents and the official Portrayal Catalogue — not approximations or shortcuts.

  • Cross-platform via Zig. Zig's build system and cross-compilation support let the same core compile to native (Linux, macOS, Windows) and WASM without code changes. Go and Zig were chosen specifically because both have excellent build systems and first-class WASM targets, making the engine usable in desktop apps, servers, and browsers from one codebase.

  • Coupled tile + style. The engine emits vector tiles (MLT or MVT) and a matching MapLibre GL style together. The same style works for MapLibre Native and MapLibre GL JS, so native and web renderers share one chart look without separate style maintenance.

  • Language-agnostic embedding. A thin C ABI (libtile57.a) bridges the Zig core to any language with C FFI. Go bindings ship in the repo; others are straightforward additions.

  • An engine anyone can build on. The end goal is an easy-to-use S-57/S-100 chart rendering engine that anyone can use to build their marine app ideas — without first becoming an IHO spec expert. Open a chart, get tiles, PNGs, or PDFs; the S-52 rules, portrayal catalogue, and mariner settings are the engine's problem. Ideas it should make easy:

    • an anchor alarm that draws your swing circle over a real chart,
    • a Windy plugin overlaying forecast weather on ENC charts,
    • a native cross-platform Qt6 C++ chartplotter,
    • a paper-style passage-plan PDF printer, a race-committee display, a tides kiosk…

tile57 decodes NOAA/IHO S-57 ENC cells and generates vector tiles by (z, x, y) — MapLibre Tiles (MLT, the default bake format; MapLibre GL JS ≥ 5.12 decodes them natively) or Mapbox Vector Tiles (--format mvt) — running the official IHO S-101 Portrayal Catalogue in embedded Lua to produce S-52 nautical portrayal. Alongside the tiles it emits a MapLibre GL style and the portrayal assets it references — colour tables, line styles, and the sprite

  • area-fill pattern atlases — so a renderer like MapLibre can draw a chart directly.

It is high-performance and low-memory by design:

  • Lazy, per-cell work. A multi-cell ENC_ROOT is indexed cheaply (band + bbox); cells are parsed and portrayed only when a requested tile needs them, then held under an LRU bound. A streaming open reads a cell's bytes on demand (and frees them on eviction), so a host holds only the working set — not the whole catalogue.
  • Band-streamed bakes. Baking an ENC_ROOT to one PMTiles archive streams band-by-band (finest → coarsest, best-band dedup), so peak memory tracks the largest single band.
  • Pure-Zig core. The foundational format/encode packages have no libc; only the Lua portrayal + sprite rasterizer pull in C.

Pipeline

S-57 ENC cell (.000)
   │  ISO 8211 decode                    src/s57/iso8211.zig
   ▼
S-57 feature + geometry model            src/s57/
   │  S-101 portrayal (embedded Lua)     src/portray/ + src/s100/
   ▼
portrayal instruction stream
   │  scene generation                   src/scene/  (project + clip + draw calls)
   ▼
render Surface ──► MVT / MLT tiles (src/tiles/)  +  MapLibre style.json + assets
             └───► PNG raster / vector PDF / terminal text (src/render/)

The stages are separate Zig modules — s57 (including its ISO 8211 decoder), s100, tiles, render, scene, assets — pure Zig with no libc; only the Lua portrayal (portray) and the sprite rasterizer (sprite) pull in C. See the architecture docs.

Use it from Zig

Add tile57 as a dependency, then @import("tile57"):

const tile57 = @import("tile57");

// Open an on-disk ENC_ROOT directory (or a single .000 file) as a streaming chart.
var chart = try tile57.Chart.openPath("ENC_ROOT/", null, true);
defer chart.deinit();

if (try chart.tile(z, x, y)) |mvt| {   // decompressed MVT bytes, or null if empty
    defer tile57.freeBytes(mvt);
    // … hand to your renderer …
}

Chart.openPath streams cells on demand (working-set only); Chart.openBytes opens a single in-memory cell. See the Zig API docs.

Use it from C

The same engine behind a thin C ABI (include/tile57.h):

// Open an on-disk ENC_ROOT directory (or a single .000 file).
tile57_chart *chart = tile57_chart_open("ENC_ROOT/");
uint8_t *mvt; size_t n;
if (tile57_chart_tile(chart, z, x, y, &mvt, &n) == TILE57_TILE_OK) {
    /* … render mvt … */
    tile57_free(mvt, n);
}
tile57_chart_close(chart);

libtile57.a also exposes the ENC_ROOT bake, the MapLibre style builder, and the asset/atlas generators. See the C API docs.

The tile57 CLI

The offline tool bakes charts and emits portrayal assets:

zig build                                    # builds zig-out/bin/tile57
tile57 bake CELL.000 -o out/                 # one cell -> bundle (tiles + style + assets + manifest)
tile57 bake ENC_ROOT -o out/                 # whole catalogue, band-streamed -> same bundle
tile57 assets   -o assets/                   # colortables + linestyles + sprite + patterns
tile57 png ENC_ROOT --view -76.48,38.974,15 --size 1600x1200 -o chart.png
tile57 pdf ENC_ROOT --view -76.48,38.974,15 --size 1600x1200 -o chart.pdf
tile57 ascii CELL.000 --view -76.48,38.974,13 --ansi --tui    # the chart in your terminal

Build

The Zig engine + CLI need only Zig 0.16:

git submodule update --init --recursive   # vendored S-101 catalogue
zig build && zig build test

Full instructions: docs/installation.

Documentation

Docs source lives in docs/: intro, getting started, the Zig API, the C API, the architecture, and the tile schema. See also CHANGELOG.md.

License

tile57's own code is MIT © Jeremy Collins. It embeds the IHO S-101 Portrayal Catalogue (© IHO) and vendors nanosvg (zlib) + stb_image_write (public domain). NOAA ENC charts are U.S. public domain and not for navigation.

About

⚓ A high-performance, low-memory S-57 → MVT vector-tile + S-52 style engine. Turns IHO S-57 ENC cells into Mapbox Vector Tiles plus a MapLibre S-52 style and its portrayal assets — embeddable from Zig or C.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Contributors