Fork me on GitHub

Mapbox Vector Tile Specification

A specification for encoding tiled vector data.


A specification is an important means of setting standards around how data are created and encoded. Just like applications make assumptions about what information exist in a database, Mapbox tools make assumptions about how data are stored in vector tiles. The specification explicitly provides information about file formats & extensions, projection and bounds, and the internal structure of vector tiles. This page aims to shed some light on the specification with

  1. how to incorporate the spec into your projects
  2. examples of encoding geographic information into vector tiles
  3. highlight real-world usage of the Mapbox Vector Tile Specification
  4. keep track of specification versions

Complete spec (2.1) Report an issue

Versioning

The specification is versioned based on major.minor notation. The major version will be incremented with any technical change to the specification format or way it should be interpreted. Changes to the minor version will be reserved for any clarification or correction of clerical errors associated with the specification language.

The major version in the specification name is synonymous with the version field in a Mapbox Vector Tile layer. See the 3.1. Layers section for more details.

Current version: 2.1

Version Date of release Updates
2.1 January 19th, 2016 Correction to the wording in a few locations of the 2.0 specification.
2.0 December 4th, 2015 The focus of version 2.0 of the Mapbox Vector Tile specification is the clarification of the intent of the intial version of the specification and the definition of interior and exterior rings within polygons. The fields within the protobuffer are more clearly defined in this version of the specification and the steps for decoders and encoders are more explicity declared.
1.0.1 July 28, 2014 Update .proto file to match Protobuf style guide, changed namespace
1.0.0 April 13, 2014 First release

Format

Vector tiles are encoded as Google Protobufs (PBF), which allow for serializing structured data. For clarity, Mapbox Vector Tiles use the .mvt file suffix. The specification details are largely structured around the rules implemented in the base .proto file found here.

They are not related at all. PBFs are a format, much like XML and can take many forms. Mapbox Vector Tiles and OSM PBFs are protobuf files, but conform to completely different specifications and are used in different ways.

Encoding geometry

To encode geographic information into a vector tile a tool must convert geographic coordinates, such as latitude and longitude, into vector tile grid coordinates. Vector tiles hold no concept of geographic information. They encode points, lines, and polygons as x,y pairs relative to the top left of the grid in a right-down manner.

Vector tiles do not store spatial information as we know it. Each vector tile is a grid

Encoding example

This is a step-by-step example showing how a single vector tile encodes geometry in the grid. It follows the commands of the "pen" to encode two rings.

Commands

Step 0

An empty vector tile

The vector tile to the left is a 10x10 grid with 2 cell buffer. Let's encode some geometry to the grid. Let's start with the blue polygon.

How are geometry clipped?

Geometry clipping is not considered part of this specification.

Encoding attributes

Attributes are encoded in a series of tags that exist within a feature in the vector that have integer values that reference keys and values designating the original key:value pairs from the geometry. For large geometry, this removes redundancy for attributes that have the same keys and similar values.

Encoding attributes

Take a look at the original geojson FeatureCollection on the left and see how it's individual parts are encoded into the proper tags of the vector tile protobuf. Hover over the features and the properties of the GeoJSON.

Original geojson

{
  "type": "FeatureCollection",
    "features": [
    {
  "geometry": { ... },
  "type": "Feature",
  "properties": {
    "hello": "world",
    "h": "world",
    "count": 1.23
  }
},
    {
  "geometry": { ... },
  "type": "Feature",
  "properties": {
    "hello": "again",
    "count": 2
  }
}
  ]
}
Final vector tile

layers {
  version: 2
  name: "points"
  features: {
    id: 1
    tags: 0
tags: 0
    tags: 1
tags: 0
    tags: 2
tags: 1
    type: Point
    geometry: ...
  }
  features {
    id: 1
    tags: 0
tags: 2
    tags: 2
tags: 3
    type: Point
    geometry: ...
  }
  keys: "hello"
  keys: "h"
  keys: "count"
  values: {
    string_value: "world"
  }
  values: {
    double_value: 1.23
  }
  values: {
    string_value: "again"
  }
  values: {
    int_value: 2
  }
  extent: 4096
}
      

Winding order

Winding order refers to the direction a ring is drawn in a vector tile, either clockwise or counter-clockwise. Many geometries are multipolygons with “holes”, which are also represented as polygon rings. It is important to be able to infer winding order to extract source data from a vector tile and understand if the geometry is part of a multipolygon or a unique polygon.

In order for renderers to appropriately distinguish which polygons are holes and which are unique geometries, the specification clarifies any polygon interior rings must be oriented with the opposite winding order than their parent exterior rings and all interior rings must directly follow the exterior ring they belong to. Exterior rings must be oriented clockwise and interior rings must be oriented counter-clockwise (when viewed in screen coordinates).

The importance of winding order

The following example geometries show how encoding a ring's winding order can affect the rendered result. Each example assumes all rings are part of the same multipolygon.

Description
Winding order
Rendered
A single ring, in clockwise order is rendered as a single, solid polygon.
Ring 1: Clockwise
Two rings with the same winding order will render as two unique polygons overlapping.
Ring 1: Clockwise
Ring 2: Clockwise
Two rings, the first (exterior) ring is in clockwise order, while the second is counter-clockwise. This results in a "hole" in the final render.
Ring 1: Clockwise
Ring 2: Counter-Clockwise
Partially overlapping rings in a multipolygon with different winding orders. The second, counter-clockwise ring will be filled outside of the polygon, but not within. This is a result of even-odd filling style.
Ring 1: Clockwise
Ring 2: Counter-Clockwise
Three rings in a multipolygon that alternate winding order.
Ring 1: Clockwise
Ring 2: Counter-Clockwise
Ring 3: Clockwise

Implementations

Implementations of the Mapbox Vector Tile Specification are far and wide. Many of them fall into one of the following categories:

  • Parsers & generators: libraries that read and/or encode vector tiles, some also have command line utilities
  • Clients: web-based tools that render vector tiles that conform to the specification
  • Applications: browser-based tools for creating and visualizing vector tiles
  • Servers: support rendering and serving up vector tiles (note: the specification doesn’t go into how to do this explicitly)

A great list of tools implementing Mapbox Vector Tiles can be found at github.com/mapbox/awesome-vector-tiles.

What the spec doesn't cover

This specification is very explicit in the way a vector tile should pack data. However, there are some related concepts that this specification does not cover.

How to use vector tiles as a dataset

This specification IS NOT intended to explain how to use vector tiles as a dataset. This is something that has been considered for the future, but it will likely be a separate specification. This specification does not cover how to store, request, or share vector tiles. Consider this specification similar to how the PNG spec explains how to pack data.

Clipping

The specification does not explain how geographic data should be clipped between vector tiles since clipping, like simplification, can be executed in many ways. Mapbox specifically clips features at a buffer around the tile (see the encoding example above). Any geometry within this buffer is assumed to carry over to another tile. This is up for consideration for a future release.

Note: encoded geometry in vector tiles can actually extend beyond the bound of the tile. This means features are not required to be clipped.

A common question, when it comes to clipping is “how do renderers know which lines to connect for clipped geometry?”. This is the very reason Mapbox adds a buffer to vector tiles and clipped geometry. When it is time to render the canvas is set to the exact tile size, which sets the edges outside of the visual frame, thus the tiles all line up. Therefore, there is no need to know which nodes are part of others for rendering purposes. That being said, one could use the id field in the protobuf to store information necessary for reconstructing polygons.

Simplification

The conversion from geographic coordinates (latitude and longitude) to vector tile coordinates (x, y) is an important step, but can be implemented in many different ways prior to vector tile encoding. It is not included in this specification, but there are some important GOTCHAs we’d like to point out.

Simplification & Rounding GOTCHAs

Even though simplification is not a part of the specification, these are some tricky situations to keep in mind as you implement a simplification or rounding algorithm.

Simplification can cause invalid polygons according to the OGC standards by oversimplifying polygon rings to the point where their edges overlap. See below how simplifying one line changes the rendering of a polygon by pushing the interior ring outside of the exterior ring.

1 / 4 Polygon with a "hole" 2 / 4 Exterior (blue) and interior (red) rings 3 / 4 Simplified exterior ring 4 / 4 Invalid geometry

When spatial coordinates are converted to tile coordinates, they are rounded to integers. Simplifying (rounding) the coordinates can reverse the winding order. Consider a triangle polygon that is simplified to the vector tile grid. The rounded point can cross over the polygon and "flip" it, rendering its winding order reversed.

1 / 4 Polygon pre-simplification 2 / 4 Simplify a point to the grid 3 / 4 Simplify the second point to the grid 4 / 4 Simplifying the final point flips the triangle and reverses the winding order