Skip to main content

Internals

How the SDK actually works, for the person — or the agent — who has to change it. User-facing documentation is under Guides and Features; this section is the implementation.

Every page states its scope at the top and links out instead of repeating, so one page can be read without the rest.

Find the page you need

You are working onRead
the render path (frame, tiles, terrain, depth, labels, lighting…)Render pipeline
binary size, build time, ccache/ninja, what a profile costsBinary size & build time
PMTiles archive internalsPMTiles data source
camera and touch events — which thread, and when each firesMap events
the facade API — the C ABI, the generated property table, specs, events, callsFacade API
giving the facade's strings autocompletion, per languageAPI autocompletion
what was measured, when, and which ideas failedPerformance lab notebook
upgrading a vendored dependency, regenerating artefactsMaintenance
renaming from the CARTO SDKMigration

Repository map

Three git repositories: the SDK and two submodules. A change under libs-massif/ or libs-external/ is a commit in that submodule, then a pointer bump here.

PathWhat it is
all/native/the C++ core — layers, renderers, data sources, projections, terrain, UI
all/modules/*.iSWIG interface files; the public API surface, mirroring all/native
android/, ios/, dotnet/, winphone/platform glue (hand-written MapView wrappers live here, not in SWIG)
libs-massif/submodule: vt (GL renderer), mapnikvt, cartocss, sgre/osrm, geocoding, nml
libs-external/submodule: third-party dependencies
scripts/build scripts, SWIG generators, the Android and iOS dev benches
routing-lib/the standalone Valhalla routing library, no renderer

A public API change is breaking for every binding even when the C++ compiles, and the SWIG wrappers are never regenerated by gradle — see Building the docs and the API and BUILDING.md.

Threads

Nothing in the SDK is a free-running loop. The GL thread draws when something calls MapRenderer::requestRedraw(); everything expensive is pushed off it.

Details, and the rule that has held for every performance round, in Frame & threads.

From a tile request to a pixel

Each box has a page: Tiles & LOD, GL vector-tile renderer, 3D terrain, Labels.

Two rules that shaped the render code

1. tangram-ng is the reference implementation, and we copy it. It renders the same data on the same devices, sharply and with no see-through. Its constants are copied, not derived — every constant this project derived instead turned out wrong. Each mechanism is ported whole: half of its depth model measured worse than none of it, three times over. When comparing, read its scene files (res/scenes/*.yaml), not only its shaders; the shader defaults are overridden there. The catalogue of what differs and why is in vs tangram-ng.

2. Measurements go in the notebook, not in a comment. A number that came from a bench belongs in the performance log with its camera and method; the code keeps the constant and one clause of why.

Known gaps

Stated so silence is not mistaken for "there is nothing there":

  • Startup / first frame — ~3.8 s to first content with a warm cache, ~1.3 s of it before the first tile is requested. Measured, not yet attributed.
  • Spherical projection (RenderProjectionMode::SPHERICAL) — none of the 3D terrain work applies to it.
  • Platform specifics — iOS/UWP GL context setup and the angle-metal backend.
  • The RTT drape — the old per-tile render-target path, deliberately undocumented because it is being removed. Do not build on it.