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] arrayzoom: zoom level numberbearing: 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 identifierview: nestedMapViewState(same shape as primary)label: optional display name for the paneviewKind: 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:
docs/project-format.md: Authoritative schema documentation for all project fieldspackages/core/src/types.ts: TypeScript contracts forMapViewState,SecondaryMapView, and related interfacespackages/core/src/store.ts: Zustand store handling runtime state and JSON serialization (lines 340-365 for secondary views)packages/map/src/map-controller.ts: MapLibre GL JS integration for applyingMapViewStatepackages/map/src/cesium-camera.ts: Parallel Cesium implementation for 3-D globe views
Summary
The .geolibre.json project format achieves complete workspace serialization through:
- Primary view state in the top-level
mapViewfield with center, zoom, bearing, pitch, and optional bbox - Secondary view states in the
secondaryMapViewsarray, supporting multi-pane layouts with independent cameras and per-pane layer visibility - Layer definitions in the
layersarray, capturing source configuration, visibility, opacity, styling, and data references - Renderer flexibility through
viewKindselection 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →