How MapLibre Control Class Names Get Mirrored for the Record Video Feature in GeoLibre

GeoLibre mirrors MapLibre control class names through a static CSS selector constant named MAP_PANEL_SELECTOR that targets .maplibre-gl-html-control, .maplibre-gl-legend, .maplibre-gl-colorbar, and .geolibre-legend-panel to raster-capture on-map UI panels during video export.

The Record Video feature in GeoLibre allows users to export animated map recordings. When the Include map panels option is enabled, the application raster-captures HTML control panels, legends, and color-bars directly from the DOM and embeds them into each video frame. Since the underlying maplibre-gl-components library does not export these class names, GeoLibre's implementation mirrors them through a carefully maintained CSS selector.

The MAP_PANEL_SELECTOR Constant

In apps/geolibre-desktop/src/components/layout/RecordVideoDialog.tsx, the selector is defined as a static constant at lines 57–58:

const MAP_PANEL_SELECTOR =
  ".maplibre-gl-html-control, .maplibre-gl-legend, .maplibre-gl-colorbar, .geolibre-legend-panel";

This selector identifies four distinct panel types:

  • .maplibre-gl-html-control – the HTML control panel rendered by the Components plugin
  • .maplibre-gl-legend – the discrete symbol legend panel
  • .maplibre-gl-colorbar – the continuous color scale panel
  • .geolibre-legend-panel – GeoLibre's custom MapLegendPanel component

DOM Query During Recording

When a user initiates recording with panels enabled, the dialog queries the map container using this selector. From lines 27–30 of RecordVideoDialog.tsx:

const domOverlays = includePanels
  ? Array.from(map.getContainer().querySelectorAll<HTMLElement>(MAP_PANEL_SELECTOR))
  : null;

The resulting domOverlays array contains references to all matched DOM elements. These references are passed to recordMapCanvas in apps/geolibre-desktop/src/lib/map-recorder.ts, which handles the actual rasterization by drawing each panel onto the canvas before encoding the video frame.

Maintenance Risk and Documentation

The class names mirrored in MAP_PANEL_SELECTOR are internal implementation details of maplibre-gl-components. Because they are not part of the library's public API, version updates may change them without warning.

The repository documents this fragility in CLAUDE.md at line 96:

"MAP_PANEL_SELECTOR [...] mirrors the rendered control class names from maplibre-gl-components — maplibre-gl-html-control, maplibre-gl-legend, maplibre-gl-colorbar — so the Record Video Include map panels option can rasterize those on‑map overlays into the recording."

If the selector drifts from the library's actual rendered output, the checkbox may disable itself or panels will silently fail to appear in recordings. No build-time error occurs because these are runtime DOM queries.

Complete Usage Example

The following pattern demonstrates how the panel capture integrates into the recording workflow:

// State management for panel inclusion
const [includePanels, setIncludePanels] = useState(false);

// UI control
<Checkbox
  checked={includePanels}
  disabled={!panelsAvailable}
  onCheckedChange={setIncludePanels}
>
  {t("recordVideo.includePanels")}
</Checkbox>
// Recording invocation with captured overlays
await recordMapCanvas({
  map,
  region: mode === "region" ? region : null,
  caption: hasCaptionText(captionOpts) ? captionOpts : null,
  domOverlays,               // panels captured via MAP_PANEL_SELECTOR
  fps,
  signal: controller.signal,
  onStarted: () => setStatus("recording"),
  onElapsed: setElapsed,
});

Key Implementation Files

File Purpose
apps/geolibre-desktop/src/components/layout/RecordVideoDialog.tsx Defines MAP_PANEL_SELECTOR and executes DOM queries
apps/geolibre-desktop/src/lib/map-recorder.ts Consumes domOverlays to rasterize panels onto video frames
apps/geolibre-desktop/src/components/legend/MapLegendPanel.tsx Implements the custom .geolibre-legend-panel component
CLAUDE.md Documents the mirroring requirement for maintainers

Summary

  • Mirror strategy: GeoLibre uses a hardcoded CSS selector (MAP_PANEL_SELECTOR) to target internal MapLibre class names
  • Runtime dependency: Panel capture relies on DOM queries, not type-safe imports, making it vulnerable to upstream changes
  • Manual maintenance: Developers must verify selector accuracy whenever maplibre-gl-components is updated
  • Silent failure mode: Mismatched selectors disable features without compile-time or runtime errors

Frequently Asked Questions

What happens if maplibre-gl-components changes its class names?

The Include map panels checkbox may disable itself or the panels will fail to appear in exported videos. No error is thrown because the selector runs at runtime against the live DOM. The CLAUDE.md file explicitly instructs maintainers to verify MAP_PANEL_SELECTOR after any dependency update.

Why doesn't GeoLibre import these class names directly?

The maplibre-gl-components library does not export its rendered class names as part of its public API. They are internal implementation details generated at runtime by the Components plugin, DOM rendering logic, and legend system. Hardcoding the selector is the only available integration point.

How does recordMapCanvas use the captured DOM elements?

The function receives the domOverlays array and iterates through each element, drawing its visual representation onto the recording canvas using standard browser rasterization APIs. This embeds the UI panels into each frame of the video output before encoding.

What is .geolibre-legend-panel doing in a MapLibre selector?

This class targets GeoLibre's own MapLegendPanel component, a custom implementation separate from maplibre-gl-components. Including it in MAP_PANEL_SELECTOR ensures consistency: both external library panels and native GeoLibre panels are captured through the same query mechanism.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →