MapLibre Tile (MLT) Specification

repository·main·Indexed 19 days ago

https://github.com/maplibre/maplibre-tile-spec

A high-performance, column-oriented vector tile specification designed to replace or augment MVT for large-scale geospatial rendering. The project provides C++ and Java implementations for encoding and decoding MLT tiles, a Node.js MVT-to-MLT development server, and CLI tools for converting MVT, MBTiles, and PMTiles formats.

Tokens
59.7K
Snippets
182
Records
261
Agent score
65%

What's inside MapLibre Tile (MLT)

  1. Introduction to MapLibre Tile (MLT) format

    main

    MapLibre Tile (MLT) is a tile format designed for high-performance map rendering. It is natively supported by MapLibre GL JS and MapLibre Native, and can be served using the Martin tile server.

    Compared to the MVT format, MLT provides:

    • Higher compression: Up to 6x improvement on large tiles using a column-oriented layout and lightweight encodings.
    • Faster decoding: Optimized for SIMD/vectorization instructions.
    • Advanced data support: Includes support for linear referencing, m-values (for formats like Overture Maps/GeoParquet), 3D coordinates (elevation), and complex types (nested properties, lists, and maps).
    • GPU-ready processing: An in-memory format designed to be loaded directly into GPU buffers (e.g., WebGL polygons or WebGPU compute shaders) with minimal CPU processing.
  2. Overview of MapLibre Tile (MLT)

    main

    MapLibre Tile (MLT) is a next-generation vector tile specification designed for high-performance rendering of large-scale (planet-scale) 2D and 2.5D basemaps. It is optimized for modern graphics APIs (CPU and GPU) and addresses the limitations of the Mapbox Vector Tile (MVT) format by using a column-oriented layout.

    Key Features

    • High Compression: Up to 6x better compression on large tiles using a column-oriented layout with lightweight encodings.
    • Performance: Optimized for SIMD/vectorization and designed to be loaded into GPU buffers with minimal processing.
    • Advanced Data Support:
      • 3D coordinates (elevation).
      • Complex types (nested properties, lists, and maps).
      • Linear referencing and m-values (supporting formats like Overture Maps/GeoParquet).

    MVT Compatibility

    While MLT can represent common MVT content, its column-oriented structure is stricter. Key differences include:

    • Layer names must be non-empty.
    • Properties must have a single consistent type across a layer.
    • Missing properties are represented as typed nulls.
    • Duplicate keys on a single feature cannot be represented as multiple values.
    • Optimized encoders may reorder features.
  3. Overview of Rust-based MLT tooling and libraries

    main

    The rust/ directory contains the core Rust ecosystem for the MapLibre Tile (MLT) specification. It is primarily composed of two components:

    1. mlt-core: The foundational Rust library for handling MLT data and logic.
    2. mlt: A command-line interface (CLI) tool designed for exploring and working with MLT files.

    For specific implementation details or usage instructions, refer to the individual package READMEs.

  4. Overview of the MapLibre Tile (MLT) Rust library

    main

    The MapLibre Tile (MLT) specification is a redesigned vector tile format optimized for modern graphics APIs and large-scale (planet-scale) 2D and 2.5D basemaps. It addresses the limitations of the Mapbox Vector Tile (MVT) specification by focusing on high-performance processing and rendering.

    Key Features:

    • Improved Compression: Up to 6x better compression on large tiles using a column-oriented layout with recursive lightweight encodings.
    • High Performance: Optimized for SIMD/vectorization and designed to be loaded into GPU buffers with minimal processing.
    • Advanced Data Support: Includes support for 3D coordinates (elevation), linear referencing, m-values (for formats like GeoParquet), and complex types like nested properties, lists, and maps.
  5. Use the mlt CLI tool for MLT file operations

    main

    The mlt binary provides a suite of commands to manage, inspect, and convert MapLibre Tile (MLT) files. Use these commands to parse raw data, decode layers into readable formats, or convert existing MVT archives into the MLT format.

    mlt [command] [options]
  6. MVT to MLT compatibility and conversion notes

    main

    While MLTv1 is inspired by Mapbox Vector Tiles (MVT), it is not a byte-for-byte replacement. MLT uses a per-layer column model rather than MVT's per-feature tag/value model. When converting between the two, observe these rules:

    • Fixed Property Types: In MLT, a property name corresponds to a single column with one declared type for the entire FeatureTable. MVT data with mixed types for the same key must be normalized (e.g., via numeric widening or coercing to strings) before encoding.
    • Handling Missing Properties: MLT represents missing properties as typed null values in a column. When converting MLT back to MVT, these null values should be omitted from the feature tags.
    • Duplicate Keys: MLT allows only one value per property column per feature. Duplicate keys in MVT must be collapsed, renamed, or rejected during conversion.
    • Feature Ordering: MLT encoders may sort features by id or spatial locality to improve compression. Do not rely on the input feature order being preserved unless explicit ordering properties are used.
    • Layer Names: Layer names in MLT must be non-empty. Empty layer names are considered invalid.
  7. Understand Vertex Encoding (Delta, Dictionary, and Morton)

    main

    MLT provides several ways to encode vertex data in the VertexBuffer:

    Componentwise Delta Encoding

    Vertices are stored as interleaved (x, y) pairs using delta encoding and zigzag encoding to handle negative values efficiently.

    1. Compute delta_x = x - prev_x and delta_y = y - prev_y.
    2. Apply zigzag(n) = (n << 1) ^ (n >> 31).
    3. Output as varint pairs: [zigzag(Δx₀), zigzag(Δy₀), zigzag(Δx₁), zigzag(Δy₁), ...].

    Dictionary Encoding (Optional)

    For frequently repeating vertices, a dictionary is used. The OFFSET/VERTEX stream contains indices into a Vertex Dictionary that is sorted by Hilbert curve index for spatial locality.

    Morton Encoding (Optional)

    Vertices can be Morton-encoded (Z-order curve) for spatial optimization, enabling efficient spatial clustering and range queries. This is stored as a Morton code plus metadata (numBits, coordinateShift).

  8. Understand the MLT FeatureTable storage layout

    main

    The FeatureTable in MLT storage is organized into logical constructs, metadata, and data streams. Understanding this layout is essential for implementing encoders or decoders.

    Layout Components:

    • Logical constructs (Blue boxes): These are not persisted. Fields are reconstructed from streams based on TileSet metadata.
    • Metadata (White boxes): Describes the data structure, including FeatureTable, Stream (SM), and Feature (FM) metadata.
    • Streams (Yellow boxes): These contain the actual data.

    Key Layout Patterns:

    • Vertex vs. Feature Scoped Properties: All vertex-scoped properties are grouped together and placed before feature-scoped properties.
    • Dictionary Encoding: When using dictionary encoding for geometries or properties, a VertexOffsets stream may be present to manage variable-sized data.
    • Columnar Layout: MLT uses a columnar layout to leverage compression and efficient access.
  9. Optimize FeatureTable size via Sorting

    main

    Choosing the correct column to sort features by can significantly reduce the overall size of the FeatureTable. Because MLT uses a columnar layout, sorting allows for better compression within individual streams.

    While exhaustive testing of every possible sorting order is computationally expensive, developers should use recommended heuristics (found in the encoding schemes documentation) to determine the optimal sort column for a given layer.

  10. Encoder configuration and geometry notes

    main

    When using the C++ Encoder, be aware of the following implementation details to ensure parity with other implementations (like Java):

    • Nullable Columns: The C++ encoder can detect nullable columns automatically. To match the behavior of the Java implementation (which uses trivial presence streams), you may need to set the EncoderConfig.forceNullableColumns option.
    • Geometry Rings: Unlike the Java implementation which uses JTS and requires closed rings (later stripped during conversion), the C++ encoder encodes geometry exactly as provided. Therefore, closing vertices should not be provided in the input geometry.
  11. Layer 0x01 - MVT Compatibility

    main

    The 0x01 tag is dedicated to MVT compatibility. It provides the same data capabilities as MVT but uses a strictly defined set of encodings and optimizations (like tessellation) to ensure interoperability. If a decoder supports 0x01, it is guaranteed to parse any specification-compliant 0x01 layer.

    Structure of a 0x01 Layer:

    • name: string: The name of the layer.
    • columnCount: varint: The number of columns in the layer.
    • Columns: Each column is defined by a columnType: varint (e.g., 1 = id, 2 = geometry, 3 = int property) followed by the column data.