Skip to content

Export classes: what every construct does on emit

mlym emit compiles a document to spec-valid style.json. Not everything in the format can compile — popups are runtime behavior, a legend is DOM chrome — so every construct declares an export class: what emit does with it. There is no fourth class and no undeclared construct; a runtime construct reaching the emitter without a registration is a thrown error, not a silent drop.

ClassMeaning
exportsHas an honest style.json representation and compiles to it.
exports-with-fallbackExports with a fallback: compiles to a documented approximation (a marker becomes a symbol layer + sprite; an animated effect becomes its static preset). Reported as lossy when the visual result differs.
no-exportDoesn’t export: interactive-only; no honest style form exists. Reported by emit as a contract warning naming the construct — never silently omitted.

This table mirrors the registry in core (packages/core/src/export/registrations.ts); a drift test fails if they disagree.

ConstructClassOn emit
center / zoom / pitch / bearingexportsStyle-spec root camera properties; compile through.
stateexportsA style-spec root property; compiles through on supporting runtimes, and below the global-state floor the defaults are inlined into expressions (the inlineState gate).
layer.beforeexportsPlacement compiles honestly: the emitted layers array is ordered accordingly, and EmitResult.placements carries the intent.
imagesexportsNamed images are fetched at compile time and merged into the document sprite; layer references are rewritten to mlym:<name> so they resolve in the emitted style.
terrainexportsA style-spec root property; compiles through verbatim, and the document’s terrain wins over a basemap’s. A source that resolves to no raster-dem source is dropped and reported as lossy rather than shipped invalid.
skyexportsA style-spec root property; compiles through verbatim, and the document’s sky wins over a basemap’s. Not drawn below maplibre-gl 4.5.0 — lossy against a declared --target below that.
projectionexportsA style-spec root property; compiles through verbatim, and the document’s projection wins over a basemap’s. Globe needs maplibre-gl 5.0.0; older runtimes render mercator — lossy against a declared --target below that.
color-reliefexportsThe layer type compiles through verbatim (it is a style-spec layer); it needs maplibre-gl 5.6+ to render, so mlym emit --target below 5.6 reports it as lossy. Live, a runtime below 5.6 skips the layer with one warning.
fitToexports-with-fallbackThe fit-to-data camera lowers to a concrete center/zoom when the named source’s GeoJSON is inline (computed for a 1024×768 reference viewport — lossy, since a live map fits its own container); for fetched or tiled sources the authored center/zoom stand in, reported as lossy.
lightexportsThe style-spec root light; compiles through verbatim to the emitted style’s light, replacing any basemap light.
markersexports-with-fallbackMarkers lower to a symbol layer with generated pin sprites — the pins render in the emitted style; DOM-marker behavior (dragging, built-in popups) does not compile, reported as lossy.
layer.effectexports-with-fallbackExperimental. A shader effect has no style.json form; the emitted style carries the layer’s own static style — the effect’s fallback — with one lossy warning per effect, so --strict refuses. A registered effect may adjust that layer or return null (the layer doesn’t export) from its fallback(). See Effects.
layer.interactiveno-exportPopups, hover, and highlight are runtime behavior; attachInteractions() restores them over an exported style.
layer.legendno-exportLegend entries are chrome, not cartography.
layer.labelno-exportDisplay labels are chrome metadata.
layer.toggleableno-exportThe emitted style carries the layer’s authored visibility and no toggle.
source.refresh / source.stream / source.cache / source.loading / source.prefetchedData / source.fetchStrategy / source.refreshInterval / source.updateStrategy / source.updateKeyno-exportLive-data machinery; the emitted source carries the data present at compile time (lossy when there is none).
map.optionsno-exportMapLibre constructor options are host decisions; the emitted style uses MapLibre’s defaults.
controlsno-exportDOM chrome; the emitted map gets MapLibre’s default control set only.
legendno-exportDOM chrome; no legend surface exists in a style.
containerno-exportclassName / inline style belong to the host page.
popupsno-exportStandalone popups are DOM chrome; the emitted style renders the map without them.
parametersno-exportPresentation metadata for state keys; the values themselves export via state.
x-*no-exportExtension blocks are host-side data; never part of the emitted style.

markers was the first construct that exports with a fallback (marker icon: URLs are fetched into the sprite at emit time, like images: entries). fitTo is the second, and its lowering rewrites the root camera rather than adding layers. The experimental effects obey the same law — every effect registers a mandatory fallback(), and the layer an effect sits on is that fallback, so an exported effect is never a silent hole in the map.

<ml-map> slots are not in the table because they are not in the document: slot children are page markup the host places around the map, so mlym emit never sees them and there is nothing to export. A page that exports to vanilla maplibre-gl keeps its own markup and positions it itself.

Terminal window
mlym emit map.yaml --out dist/

Constructs that don’t export arrive as contract warnings — expected, documented drops that don’t fail --strict:

contract layers.quakes.interactive: `interactive` — Interactions (popups, hover,
highlight) are runtime behavior with no style.json form; …
contract controls: `controls` — Controls are DOM chrome; …

lossy warnings are different — something the map shows changed (a live source with no compile-time data, a fallback that approximates). Those fail --strict, because they are the cases where the exported map is not the map you authored.