How the .geolibre.json Project Format Stores Layer and View State in GeoLibre

The .geolibre.json format captures all workspace state—including map camera position and every layer definition—in a single JSON document with top-level mapView and layers fields.

GeoLibre's native project format provides complete workspace serialization, enabling users to save and reopen complex mapping projects exactly as configured. This article examines how the .geolibre.json format structures view state (camera position and multi-pane layouts) and layer state (data sources, visibility, and styling) based on the opengeos/GeoLibre source code.

Map View State: Primary and Secondary Panes

The .geolibre.json format distinguishes between a primary map view and optional secondary panes for split-screen or multi-view layouts.

Primary Map View (mapView)

The top-level mapView field stores the main camera state as a MapViewState object. According to docs/project-format.md, this includes:

  • center: [longitude, latitude] array
  • zoom: zoom level number
  • bearing: rotation in degrees (0 = north up)
  • pitch: tilt angle in degrees (0 = top-down view)
  • bbox: optional bounding box override

The TypeScript definition in packages/core/src/types.ts (lines 1005-1020) formalizes this structure:

// MapViewState definition in packages/core/src/types.ts
interface MapViewState {
  center: [number, number];
  zoom: number;
  bearing?: number;
  pitch?: number;
  bbox?: [number, number, number, number]; // [minX, minY, maxX, maxY]
}

Secondary Map Views (secondaryMapViews)

For multi-pane layouts, the secondaryMapViews array contains SecondaryMapView objects. Each secondary pane maintains independent camera state plus layout-specific overrides:

  • id: unique pane identifier
  • view: nested MapViewState (same shape as primary)
  • label: optional display name for the pane
  • viewKind: renderer type ("maplibre" or "cesium" for 2-D/3-D)
  • layerVisibility: per-layer visibility overrides keyed by layer ID

The SecondaryMapView interface appears in packages/core/src/types.ts (lines 1036-1053):

// SecondaryMapView definition in packages/core/src/types.ts
interface SecondaryMapView {
  id: string;
  view: MapViewState;
  label?: string;
  viewKind?: 'maplibre' | 'cesium';
  layerVisibility?: Record<string, boolean>;
}

The Zustand store in packages/core/src/store.ts (lines 340-365) manages runtime synchronization between these views and their JSON serialization.

Layer State: The layers Array

Every data layer in a GeoLibre project is represented as an object in the top-level layers array. The schema documented in docs/project-format.md (lines 45-74) specifies:

Property Purpose
id Unique layer identifier (referenced by layerVisibility overrides)
name Human-readable display name
type Source type: geojson, xyz, wms, vector, raster, etc.
source Type-specific source configuration
visible Boolean visibility flag
opacity Alpha value 0-1
style Renderer-specific symbology (colors, widths, labels)
geojson Inline GeoJSON data (for geojson type)
sourcePath External file reference
refreshInterval Optional auto-refresh timing in seconds
joins Attribute join configurations

Each layer's complete definition—including inline data, external references, and styling—preserves enough information to reconstruct the visualization without additional context.

Complete Project Examples

Single-Pane Project with GeoJSON Layer

{
  "version": "0.1.0",
  "name": "Sample Project",
  "mapView": {
    "center": [-122.4194, 37.7749],
    "zoom": 11,
    "bearing": 0,
    "pitch": 45
  },
  "basemapStyleUrl": "",
  "basemapVisible": true,
  "basemapOpacity": 1,
  "layers": [
    {
      "id": "layer-1",
      "name": "San Francisco Roads",
      "type": "geojson",
      "source": { "type": "geojson" },
      "visible": true,
      "opacity": 1,
      "style": {
        "fillColor": "#3b82f6",
        "strokeColor": "#1e40af",
        "strokeWidth": 2,
        "fillOpacity": 0.6
      },
      "geojson": { "type": "FeatureCollection", "features": [] },
      "sourcePath": "/data/sf-roads.geojson"
    }
  ],
  "styles": {},
  "plugins": {}
}

Split-Screen Layout with Per-Pane Visibility Overrides

{
  "version": "0.1.0",
  "name": "Split-Screen Demo",
  "mapView": { "center": [0, 0], "zoom": 2, "bearing": 0, "pitch": 0 },
  "basemapStyleUrl": "",
  "basemapVisible": true,
  "layers": [
    {
      "id": "layer-1",
      "name": "Global Roads",
      "type": "geojson",
      "source": { "type": "geojson" },
      "visible": true,
      "opacity": 1,
      "style": { "strokeColor": "#ef4444", "strokeWidth": 1 }
    }
  ],
  "secondaryMapViews": [
    {
      "id": "pane-2",
      "view": { "center": [0, 0], "zoom": 5, "bearing": 0, "pitch": 0 },
      "label": "Zoomed-In",
      "viewKind": "maplibre",
      "layerVisibility": { "layer-1": false }
    }
  ],
  "styles": {},
  "plugins": {}
}

In this configuration, the secondary pane (pane-2) displays a zoomed-in view with the road layer hidden, demonstrating how layerVisibility overrides global layer settings per pane.

Key Implementation Files

The .geolibre.json persistence layer spans several packages in the opengeos/GeoLibre repository:

Summary

The .geolibre.json project format achieves complete workspace serialization through:

  • Primary view state in the top-level mapView field with center, zoom, bearing, pitch, and optional bbox
  • Secondary view states in the secondaryMapViews array, supporting multi-pane layouts with independent cameras and per-pane layer visibility
  • Layer definitions in the layers array, capturing source configuration, visibility, opacity, styling, and data references
  • Renderer flexibility through viewKind selection between MapLibre 2-D and Cesium 3-D on a per-pane basis

This structure enables GeoLibre to restore exact visual state across sessions while remaining human-readable and version-controllable.

Frequently Asked Questions

What is the maximum number of secondary map views supported in a .geolibre.json file?

The secondaryMapViews field is defined as an array with no hardcoded limit in the TypeScript types. Practical constraints depend on browser performance and available screen real estate for rendering multiple map instances simultaneously.

How does GeoLibre handle layer visibility when a secondary pane has no visibility override specified?

Per the SecondaryMapView interface definition, layerVisibility is optional. When omitted or when a layer ID is not present in the record, the secondary pane inherits the global layer visibility state from the main layers array.

Can different secondary panes use different rendering engines in the same project?

Yes. The viewKind property on each SecondaryMapView accepts "maplibre" or "cesium" independently. This allows mixed 2-D and 3-D visualization within a single project file, with packages/map/src/map-controller.ts and packages/map/src/cesium-camera.ts handling their respective renderers.

Where is the ground truth for the .geolibre.json schema specification?

The authoritative documentation resides in docs/project-format.md at the repository root. This file defines all valid fields, their types, and their semantic meaning, while packages/core/src/types.ts provides the runtime TypeScript implementation that enforces these contracts.

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 →