State of the Art Styling in CARTO VL


This post may describe functionality for an old version of CARTO. Find out about the latest and cloud-native version here.
State of the Art Styling in CARTO VL

One of the most welcomed features of modern vector renderers is the performance advantage they bring to the table. While SVG and Canvas renderers have been developed in the past  it has been WebGL that has skyrocketed performance. Modern GPU architectures can easily outperform CPUs by an order of magnitude in parallel scenarios like rendering. Having to compete with a scripting language  it is no surprise that WebGL and GPUs have gained the performance crown.


GPU vs CPU performance evolution

However  while previous WebGL renderers used the GPU for the final rendering pass  they didn't exploit WebGL’s full potential. Every renderer  whether it is GPU based or not  consists of two phases: a styling phase in which features get assigned some rendering properties (like color and point size) based on the feature properties (type  price)  and a draw pass in which geometries and their rendering properties are used to paint onto the final image or canvas.

Previous technologies already used WebGL for performing the drawing pass  however  the styling process was always delegated to slow Javascript code.

We  at CARTO  have unleashed the full potential behind WebGL by developing  a fully GPU accelerated library for map making: CARTO VL.

CARTO VL Rendering Pipeline

Of course  a fully accelerated pipeline comes with its own disadvantages. Although modern GPU architectures have been designed with the focus on giving more flexibility (see the recent trends in GPGPU)  WebGL is based on OpenGL ES 2.0  a 2007 standard designed not only for desktops but for mobile devices too.

Therefore  we had to be a little bit creative in the way we designed our rendering pipeline. In particular  we used 2D textures as storage for feature properties (type  price  …) and feature rendering properties (color  point size  …).


carto vl core architecture pipeline

Our rendering pipeline is made up of the following components:

  • JS array buffers with geometries and feature properties. These buffers are encoded from GeoJSON or from MVT tiles and they are used to push the information to WebGL.
  • WebGL Vertex Buffer Object with feature geometries. Point centers and the vertices of the triangulated polygons and lines are placed here.
  • WebGL FP32 textures with feature properties. Strings that act as categories are uniquely identified and transformed into unique integer IDs.
  • WebGL Vertex Buffer Object with feature ID pointers to the textures  to keep the connecting link between the geometry Vertex Buffer Object and its associated feature properties and rendering properties.
  • JS tree that represents the styling of the visualization. This will generate the following shaders:
  • WebGL Shaders with the styling information that transforms feature properties into feature rendering properties. This is CARTO VL’s secret ingredient. These dynamically generated shaders are used to generate the next textures by performing Render To Texture.
  • WebGL Shaders with the final rendering pass. These are usually fixed shaders  except when rendering images or translating the geometries.
  • WebGL Textures with feature rendering properties. These are used by the final rendering pass.


This pipeline allows us to restyle features by changing the styling shaders and performing the necessary WebGL drawing calls  removing the need to do expensive CPU to GPU communication and the need to style the features on JS.

Having super-fast restyling is good for general performance  but it is critical for making temporal maps in which the restyling must be done at each frame without stopping. This pipeline allows the display of a large number of animated features at 60 frames per second.

Link to map

 Interested in getting started with CARTO VL today?Visit our Developer Center!

Moreover  the flexibility of our pipeline allows support for all geometry types (points  lines  and polygons) and enables the combination of temporal filtering and all other CARTO VL expressions.  Making complex filters like "animate buildings by the year they were built  but don't show buildings with less than two floors" possible.

color: ramp(linear($yearbuilt 1900 2018) prism) 
filter: $numfloors > 2 and animation(linear($yearbuilt 1900 2018)  20  fade(0.5  hold))

Link to map

Special thanks to Mamata Akella  CARTO's Head of Cartography  for her support in the creation of the maps in this post.